54

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
  • 3,474
  • 7
  • 35
  • 89
  • 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

8 Answers8

63

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)
}
starball
  • 20,030
  • 7
  • 43
  • 238
Akshay Seth
  • 1,224
  • 1
  • 12
  • 11
  • 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
20

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,709
  • 1
  • 16
  • 23
Maxime
  • 415
  • 3
  • 9
8

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.
  • 344
  • 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,425
  • 12
  • 22
6

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,895
  • 1
  • 30
  • 29
5

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
  • 369
  • 5
  • 8
1

Elegant & with TypeScript.

import axios, { AxiosResponse, AxiosError } 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: AxiosError) => {
  if (error instanceof Error) {
    console.error(
      "Error with fetching ..., details: ",
      error
    );
  }
});
Valentine Shi
  • 6,604
  • 4
  • 46
  • 46
Daniel Danielecki
  • 8,508
  • 6
  • 68
  • 94
0

const getPass = (e) => {
    e.preventDefault()
    const post = { userName: userName } 
        axios.post("/", post)    //axios.post(keys.sessionURL, {email: keys.verificationEmail,password: keys.verificationPassword,})
        .then(res => {
            if(!res.ok){
                throw Error('Network Error'); //error from axios
            }
            return res.json(); 
        }).catch(err => {
            console.log(err.message) //to display the error to your user just use the useState to define your error
            })
  }

const getPass = (e) => {
    e.preventDefault()
    const post = { userName: userName } 
        axios.post("/", post)    //axios.post(keys.sessionURL, {email: keys.verificationEmail,password: keys.verificationPassword,})
        .then(res => {
            if(!res.ok){
                throw Error('Network Error'); //error from axios
            }
            return res.json(); 
        }).catch(err => {
            console.log(err.message) //to display the error to your user just use the useState to define your error
            })
  }
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 19 '23 at 01:44