39

Here's my chunk of code:

  const getToken = async () => {
    try {
      const token = await axios.post(keys.sessionURL, {
        email: keys.verificationEmail,
        password: keys.verificationPassword,
      });
    } catch (err) {
      throw new Error('Unable to establish a login session.'); // here I'd like to send the error to the user instead
    }
  };

So as you can see I'm connecting to external server in order to get a token. And that works. Now, I'd like to catch an error but this time not with 'throw new error' but I'd like to send it to the user, so I'd like to have something like this instead:

res.status(401).send('Unable to get a token');

But because I'm not inside the route handler I cannot use 'res'. How can I send it to the user then?

Thank you!

Murakami
  • 2,654
  • 5
  • 27
  • 68
  • You may await getToken in your route handler and catch the exception there. Then you will have access to your res object. I can show you with an example if you provide more info about how you call getToken – Maxime Sep 26 '18 at 07:37

7 Answers7

52

For axios version-0.19.0 below code worked after hours of struggling with async await.Not sure about other versions though!

catch(error){
console.log(error.response.data.error)
}

Hope that helps!

Akshay Seth
  • 1,084
  • 11
  • 11
  • I feel this is the best answer to this question by far. Unlike the others, it actually uses the data provided by the triggered error and allows for further processing from that. Good one, Akshay – Irregular Shed Sep 02 '20 at 17:11
  • 1
    The answer should be voted as the correct answer. It allows the front end to retrieve the error coming from the backend. this saved my project – Ufenei augustine Feb 09 '21 at 06:01
  • Struggles for a hour now, this saved me! – Đặng Quốc Trung Jun 12 '21 at 18:16
  • it show error TypeError: Cannot read properties of undefined (reading 'data') – huykon225 Jan 11 '22 at 02:18
  • @huykon225 You should check if error.response is defined first. In you case there is probably no response at all so directly check the error object. – Roel Apr 21 '22 at 08:29
11

You can keep almost the same function

const getToken = async () => {
  try {
    const token = await axios.post(keys.sessionURL, {
      email: keys.verificationEmail,
      password: keys.verificationPassword,
    })
  } catch (err) {
    throw new Error('Unable to get a token.')
  }
}

Then from your route handler just catch the eventual exception

app.get('/endpoint', async (req, res) => {
  try {
    const token = await getToken()

    // Do your stuff with the token
    // ...

  } catch (err) {
     // Error handling here
     return res.status(401).send(err.message);
  }
})

The default js exception system works well to pass error data through the call stack.

its4zahoor
  • 1,489
  • 1
  • 15
  • 19
Maxime
  • 325
  • 2
  • 9
7

In my solution I use:

try{
    let responseData = await axios.get(this.apiBookGetBookPages + bookId, headers);
    console.log(responseData);
}catch(error){
    console.log(Object.keys(error), error.message);
}

If something failed we will get en error like this:

[ 'config', 'request', 'response', 'isAxiosError', 'toJSON' ] 
'Request failed with status code 401'

We can also get status code:

...
}catch(error){
    if(error.response && error.response.status == 401){
            console.log('Token not valid!');
    }
}
Lev K.
  • 328
  • 4
  • 4
6

you keep a flag like isAuthError and if error occurs send it as true and in the main function if the flag isAuthError is true throw the err and handle in catch otherwise perform your operations. I've added an example below. hope it helps

const getToken = async () => {
    try {
      const token = await axios.post(keys.sessionURL, {
        email: keys.verificationEmail,
        password: keys.verificationPassword,
      });
      return {token, isAuthError: false};
    } catch (err) {
      // throw new Error('Unable to establish a login session.'); // here I'd like to send the error to the user instead
      return {err, isAuthError: true};
    }
  };

mainFunction

app.post('/login', async (req, res)=>{
  try{
    // some validations

    let data = await getToken();
    if( data.isAuthError){
      throw data.err;
    }
    let token = data.token;
    //do further required operations
  }catch(err){
     //handle your error here with whatever status you need
     return res.status(500).send(err);
  }
})
Atishay Jain
  • 1,345
  • 11
  • 21
4

try/catch is not a good solution. It's meant to catch runtime error, not HTTP error coming from axios if error is processed by interceptor and then passed back to caller via return Promise.reject(error);

here is interceptor example

axios.interceptors.response.use(
  response => {
    //maybe process here
    return response;
  },
  error => {
    //do some global magic with error and pass back to caller
    return Promise.reject(error);
  }
);

Let's start with try/catch example that won't work

for(let i=0; i<5;i++) {

    try{
       const result = async axios.get(`${/item/{i}}`);
    }
    catch(error) {
       //error undefined here, you would expect an error from pattern like axios.get(...).then(...).catch(real_http_error) 
    }
}

I found this pattern to work. Let say you want to make calls in a loop to make avoid multiple http call due to async nature of JS.

for(let i=0; i<5;i++) {

    const result = async axios.get(`${/item/{i}}`).catch(error) {  //chain catch despite async keyword
       //now you access http error and you can do something with it
       //but calling break; or return; won't break for loop because you are in a callback
    }

    if(!result) { //due to http error
        continute; //keep looping for next call
        //or break; to stop processing after 1st error
    }
    
    //process response here, result.data...
}
Pawel Cioch
  • 2,652
  • 1
  • 25
  • 29
1

Keep the grace of async / await :

const result = await axios.post('/url', params)
    .catch((err) => {
       // deal with err, such as toggle loading state, recover click and scroll.
       this.loading = false;
       // recover the reject state before.
       return Promise.reject(err);
    });

this.data = result; // not exec when reject
Dreamoon
  • 159
  • 1
  • 6
0

Elegant & with TypeScript.

import axios, { AxiosResponse } from "axios";
...

const response: void | AxiosResponse<any, any> = await axios({
  headers: {
    Authorization: `Bearer ${XYZ}`,
    Accept: "application/json",
  },
  method: "GET",
  params: {
    ...
  },
  url: "https://api.abcd.com/...",
}).catch((error: unknown) => {
  if (error instanceof Error) {
    console.error(
      "Error with fetching ..., details: ",
      error
    );
  }
});
Daniel Danielecki
  • 5,838
  • 4
  • 44
  • 72