Fetch: what does response do?

I’m writing a React component that fetches data from an API and renders it.

My code looks like this:

class Menu extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      apiKey: "",
      name: "",
      description: "",
      price: 0
    };
  }

  componentDidMount() {
    console.log("mounted");
    fetch(
      "https://raw.githubusercontent.com/angel-design/ubiquitous-funicular/master/sandbox/response.json"
    )
      .then(fetched => {
        console.log("fetched");
      })
      .then(response => response.json())
      .then(json => {
        console.log("response logged");
      })
      .then(data =>
        this.setState({
          apiKey: data.apiKey,
          name: data.name,
          description: data.description,
          price: data.basePrice
        })
      )
      .then(stateSet => {
        console.log(this.state);
      })
      .catch(error => {
        console.log("error");
      });
  }

  render() {
    return <div>Hi</div>;
  }
}

My problem is:

  • The console log throws up an error after the component is mounted and the data fetched and before the response is logged.

  • What does the response promise do, and why is it creating an error?

Thank you for your time and help!

Instead of this:

console.log("error")

Do this:

console.error(error)

That’ll show the actual error you’re getting as an error in the console.

Also, the fetch API will not throw an exception if it encounters an HTTP error response (this is one major difference from axios). You need to check response.ok before slurping up the json data.

1 Like

Thank you so much! I updated the code:

componentDidMount() {
    console.log("mounted");
    fetch(
      "http://raw.githubusercontent.com/angel-design/ubiquitous-funicular/master/sandbox/response.json"
    )
      .then(fetched => {
        console.log("fetched");
      })
      .then(response => response.ok ? response.json(): console.log(response.statusText))
      .then(json => {
        console.log("response logged");
      })
      .then(data =>
        this.setState({
          apiKey: data.apiKey,
          name: data.name,
          description: data.description,
          price: data.basePrice
        })
      )
      .then(stateSet => {
        console.log(this.state);
      })
      .catch(error => {
        console.log(error);
      });
  }

The console log telling me that the error is [object Error] {} which is surprisingly difficult to google for. Do you know what I should be troubleshooting?

Error is an object, you’re just logging that error object. It has a field called message which contains the error text.

And the then calls work in a chain.

Fetch something, let's call it A
  Then use A, return B
  Then use B, return C
  Then use C, return D
  Catch any errors that have happened in the chain

(Edit: bearing that in mind, this link in the chain doesn’t pass the thing you want onto the next then: then(json => { console.log("response logged"); }), so the data argument in the next then will be undefined)

So if the response is not ok, and you’re catching the errors, then you need to throw an error.

.then(response => {
  if (response.ok) {
    return response;
  } else {
    throw new Error(response.statusText);
    // Promise is rejected and control jumps to
    // the nearest error handler (nearest catch)
  }
})

Then

.catch(error => console.log(error.message)
1 Like

Thank you! The error that is showing up is “Failed to fetch” on Chrome and “NetworkError when attempting to fetch resource.” on Firefox. Going into the network monitor, I see that my GET request to the json file has been blocked.

However, if I change the url to a different API (https://hn.algolia.com/api/v1/search?query=redux), I can access it fine. So it appears that the problem is that my json file on Github is being blocked.

Adding 'Accept': '*/*' to the header doesn’t do anything, nor does adding 'Content-Type': 'application/json' to the header. What should I do to fetch my file?

First of all, you should be using https instead of http for the request.

Next, your second then returns undefined, because console.log’s return value is undefined when you call it with console.log(“response logged”). I would suggest removing the second then (and even the first then), because you could always put console.log statements with the other then methods if you feel they are necessary.

I would not use a ternary expression here. It would be clearer with a simple if statement.

.then(response => {
  if(response.ok) {
    return response.json();
  }
  throw new Error(response.statusText);
})

That sounds like the FCC challenge editor console, which is not suitable for real-world use. Chrome and Firefox should show you the actual error object on a red background.