Go Fetch - Recreating Fetch

Learning Goals

  • Break down the Fetch API to understand what we get back
  • Create our own fetch that mimics how the Fetch API behaves

Basic Setup

We are going to be working to recreate fetch from scratch! Let’s use the following CodePen to have a basic starting point for our app. It’s pretty simple - a button that gives us advice once we click it. Dope.

See the Pen Go Fetch - Starter by eric weissman (@eric_turing) on CodePen.

Let’s start by getting an event listener set up to listen for a click on the button. When we click the button, we want to make a fetch to the Advice API. Take a look at the documentation to see how we can get some random life advice!

Take a few minutes to get your app set up to make a fetch to this API and display the data on the page! If you’re really stuck, you can see a solution below!

Setup Solution

<button type="button" name="button">Go Fetch</button>
<section id="advice-area">

</section>
const button = document.querySelector('button');
button.addEventListener('click', getAdvice);

const getAdvice = () => {
  const advice = fetch('https://api.adviceslip.com/advice')
  .then(res => res.json())
  .then(advice => appendAdvice(advice))
}

const appendAdvice = advice => {
  document.querySelector('section').insertAdjacentHTML('afterend', `
  <h3>${advice.slip.advice}</h3>
  `)
}

Breaking Down Fetch

Our goal today is to make our own version of fetch that will give us back a piece of life advice as if we were actually making a request to the Advice API.

But why are we doing this? When we start discussing async testing, there are going to be situations where we will need to mock out certain functionality that we didn’t write ourselves (such as the fetch API) in order to get our tests to work correctly. This is our first dive into breaking down one of these methods and trying to make a workable version on our own!

Step 1 - Reassigning Fetch

fetch is a method that is given to us on the Window object and allows us to utilize the Fetch API to make network requests.

If we break this down, fetch is a method (or function) to will return us some data that we can use later in our app. So to get things rolling, we need to reassign fetch to be a function!

Reassigning Fetch

  window.fetch = () => {}

Step 2 - What does fetch return?

When we use the fetch API, we are making a network request to get data that we can use in our app. But as we know, it doesn’t just come back all neatly packaged for us. So what DO we get back from a fetch request?

That’s right… A PROMISE!

So how can we adjust our handmade fetch to handle this? Well for today, let’s just worry about getting a Promise back that has been resolved (Happy Path).

Mocking Fetch’s Return

  window.fetch = () => {
    return Promise.resolve({})
  }

Let’s break down what’s happening here…

  • We are returning a Promise object from the fetch
  • We are calling artificially creating a resolved Promise by using .resolve() on our Promise
  • This will give us back a Promise of the resolved value, which in the case of fetch, returns us the Response object!

Step 3 - Diving Into the Response Object

Think back to other network requests you have made. After we make our initial fetch, we are returned a Promise! This Promise returns us the response object which is why we typically name this res or res within our .then() block.

Have you actually taken a look at what the response object looks like? If not, let’s open our console and check it out!

  fetch('https://api.adviceslip.com/advice')
    .then(res => console.log(res))

Your response object should look something like this…

There is a lot of data in the response object and we don’t necessarily need to use all of it in our mocked out version of fetch.

We definitely want to include the ok property to convey that this Promise has resolved as expected. We can refactor our fetch to reflect this.

Response Object Pt. 1

window.fetch = () => {
	return Promise.resolve({
		ok: true,
	})
}

Step 4 - Getting Data From the Response Object

Thinking back to our original fetch, what did we need to do to actually extract data from the Response object? We had to call .json() on the Response! Take a few minutes to review the documentation on this method.

As outlined in the docs, .json() can ONLY be called on a Response object! We can’t just be using this method all willy nilly in our codebase. It only works on a Response object!

As per the docs, the .json() method returns a Promise that resolves to a JS object that can be represented in JSON (including objects, arrays, etc.) But remember, we didn’t write this method! But we can mock out the same functionality that would return us the data we want back!

But wait…

Step 5 - What Data DO We Want Back?

In this case, we are trying to make a mocked out version of the fetch to the Advice API. So, let’s open Postman to see what a response looks like when we hit the Advice API. It should look something like this…

  {
    "slip": {
      "advice": "State the problem in words as clearly as possible.",
      "slip_id":"154"
    }
  }

Great! We don’t necessarily care about all of this information, but we definitely want the advice so we can render it on the page!

Let’s create a variable to hold this information and then we can use that when we want to keep building our fetch!

Creating a Mock Response

const mockResponse = {
  slip: {
    advice: 'State the problem in words as clearly as possible.'
  }
}

Step 6 - Finishing Out Our Fetch!

So we know we need to mock out the .json() method of our Response object. When we call that in the real world, is parses the data and returns it to us in a format we can work in. We just created the data that we want back in our mockResponse - so, put it all together!

Try to finish out our re-write of fetch! If it works correctly, your App should be able to render the same joke as you have in your mockResponse!

Recreating Fetch Solution

window.fetch = () => {
  return Promise.resolve({
    ok: true,
    json: () => Promise.resolve(mockResponse)
  })
}

Wrapping Up

To review, we were able to make our own version of fetch that allowed us to simulate a major component of FE engineering that we didn’t create ourselves!

This pattern of mocking out functionality we didn’t write, especially that of fetch, will be a major benefit for us when we learn about asynchronous testing.

Exit Ticket

Take a few minutes in your journal to answer the following questions:

  • What “aha” moments did you have?
  • Which concepts are the fuzziest for you right now?
  • Which concepts are the clearest for you right now?

Lesson Search Results

Showing top 10 results