Forcing a catch in a Promise

I’m working on my api calls within my client code and I’m having some trouble on figuring out how to handle errors on the server. Specifically 4xx and 5xx errors. One of the solutions I came across was checking the ok property on the response object immediately after the request completes.

If that is false, I manually throw an error with a string message describing the error. This works well. It rejects the Promise and throws the error. However, it immediately terminates the execution and the code I have on my react method is never reached. I’m sure the reason this is the case is that I’m rejecting the promise, thus completing the life cycle of it.

Is there a better way to approach this?

export const authenticate = async function(payload) {
    const options = {
        method: 'POST',
        body: JSON.stringify(payload),
        headers: {
            "Content-Type": "application/json"
        }
    }
    const response = await fetch(`${base}/login`,options).then((res) => {
        console.log(res.ok)
        if(!res.ok) {
            throw new Error('The credentials you provided are invalid')
        } else {
            return res.json();
        }
    }).catch((err) => {
        return Promise.reject(err)
    })

    localStorage.setItem('Bearer', response.token)
    
}

Skipping the Promise.reject() and just returning my err in catch doesn’t return anything

...
 }).catch((err) => {
        return Promise.reject(err)
    })
...

Let me know if you need more details or code :slightly_smiling_face:

This is because you are throwing the error to another promise, which immediately rejects. But it doesn’t look like you are catching that one. And if a promise doesn’t have a catch block, it will terminate execution

from mdn

The Promise returned by catch() is rejected if… returns a Promise which is itself rejected; otherwise, it is resolved.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch

Still, you should handle errors in the client and UI gracefully. Meaning that your response should always return some kind of result, so that React has something to render.


const response = await fetch(`${base}/login`,options).then((res) => {
        console.log(res.ok)
        if(!res.ok) {
            throw new Error('The credentials you provided are invalid')
        } else {
            return res.json();
        }
    }).catch((err) => {
    // return error object to the client.
        return err
    })

then in the client

if (err.message === 'The credentials you provided are invalid') // render something

@JM-Mendez You are absolutely right. However, the issue I’m experiencing is that when the promise is rejected and passed into the catch, undefined is being returned when my expected should be the error object

const response = await fetch(`${base}/login`,options).then((res) => {
        console.log(res.ok)
        if(!res.ok) {
            throw new Error('The credentials you provided are invalid')
        } else {
            return res.json();
        }
    }).catch((err) => {
        return err //the client receives undefined
    })

I may be misunderstanding but this is my sticking point

Ok, so then it might be because you’re using a catch method without the try block. Take a look at this portion of mdn’s await description

I’ve only ever used async/await with try/catch blocks, and not chained catch methods, so I can’t verify it for you.

But it seems that if you use the chained catch method, then undefined will be returned on rejection. Which is what you’re seeing.

Try it with a try/catch block instead, and see if it works. So something like

export const authenticate = async function(payload) {
  const options = {
    method: 'POST',
    body: JSON.stringify(payload),
    headers: {
      'Content-Type': 'application/json',
    },
  }

  try {
    const response = await fetch(`${base}/login`, options)
    if (!response.ok) {
      throw new Error('The credentials you provided are invalid')
    } else {
      // this is also a promise
      const json = await response.json()
      localStorage.setItem('Bearer', json.token)
    }
  } catch (err) {
    return err
  }
}

I think that should solve your issue. If it doesn’t, then I’d need a repo of some kind if you want me to help to continue debugging it.

I ended up creating my own error handler in my api.js file but for one of the requests I used the try/catch block. That worked a lot better. It would still ‘terminate’ but I was able to access the Error object.