How to handle bad request in fetch()

Viewed 1310

I know this is a basic and often recurring issue, but I am still unable to make it work.

I have the following code

handleAdd = (event: any): void => {
        
    // ...
        
    // create new task
    try {
          // send data to backend
          fetch(`/api/tasks?name=${name}&priority=${priority}`, { method: 'post' })
                .then(response => { if (!response.ok) {  
                       throw new Error('error => how to get bad request message here?') } })
    }
    // handle exception
    catch (e) {
          console.log(e);
          this.setState({
               isError: true,
               errorMessage: e.message
          });
    }
}

the API returns 400 with some error message

enter image description here

but in the browser I get

enter image description here

So I have two questions

  • Why the throw new Error() in fetch does not goes to catch(e) {} method (if the error is outside fetch function, it works well)? How to rewrite this line to get into catch method? I think it has something to do with the Promise object?
  • How to get the bad request message from response object?

update, working solution


fetch(`/api/tasks?name=${name}&priority=${priority}`, { method: 'post' })
    .then(response => {
        if (!response.ok) {
                  
            response.text().then(function (text) {
                throw Error(text);
            }).catch((e) => {
                this.setError(e.message);
            });

        }
    })
  • how to get response.text() into the Error exception?
3 Answers

when using promises, you can choose between chaining your promise with then/catch or using async/await.

if you are chaining promise you should chain with a catch:

handleAdd = (event: any): void => {
    // send data to backend
    fetch(`/api/tasks?name=${name}&priority=${priority}`, { method: 'post' })
        .then(response => { if (!response.ok) {  
              throw new Error('error => how to get bad request message here?') } }
        ).catch((e) => {
            console.log(e);
            this.setState({
              isError: true,
              errorMessage: e.message
            })
        });
}

if you prefer you can change your function to async/await. with that you would use a try/catch block:

// mark your function as async
handleAdd = async (event: any): void => {

  try {
    // await your fetch response
    const response = await fetch(`/api/tasks?name=${name}&priority=${priority}`, { method: 'post' })
    if (!response.ok) {  
      throw new Error('error => how to get bad request message here?')
    }  
  }
  // handle exception
  catch (e) {
    console.log(e);
    this.setState({
          isError: true,
          errorMessage: e.message
    });
  }
}

I'd imagine if you are not using React, it could be that you have a local or global error or warning message area, so that the

fetch
  .then()
  .catch(err => {   
     // display "try again later" here
  });

But since you are using React and probably Redux, you could dispatch an action NETWORK_ERROR instead so that the reducer will create that error message "try again later":

fetch
  .then()
  .catch(err => {   
     // dispatch the action for NETWORK_ERROR here
  });

try it this way and you are good to go

fetch(`/api/tasks?name=${name}&priority=${priority}`, { method: 'post' })
       .then(response => { if (!response.ok) {  
               throw new Error('error => how to get bad request message here?') } 
}).catch(error => {
        // handle the error here
        console.log(e);
    });
Related