0

I have the following code, simplified to leave out unnecessaries:

try {
  const response = await axios.put(url, {});
  if ( response.status === 200 ) {
    MicroService.action(data);
  }
} catch ( error ) {
  // user is not signed in, so send to create-account/sign-in
  if (error.status === 401) {
    MicroService.otherAction(data);
  } else {
    console.error(`The server returned an unexpected ${error.status} error upon attempting to hit ${url}`);
  }
}

The problem is that the catch clause also catches any error that occurs in the fourth line, MicroService.action(data). I only want to catch an error with the axios call on line 2, no other error should be silenced.

But if I take the MicroService.action(data) and move it to after the catch, then it happens even if the try fails, which is wrong. It should only happen if the try succeeds.

I could set a variable in the try clause, e.g. if (response.status === 200) let success = true;, and then check that variable after the catch clause. But that feels messy and inelegant for anything but the simplest possible case.

Is there a better way of doing this?

temporary_user_name
  • 35,956
  • 47
  • 141
  • 220
  • Have you tried placing a `finally` block after the catch?? That way it would execute after your axios call finishes. However, you would have to declare your `response` variable as a `let` and move it outside of your try. [MDN Try/Catch](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch#Syntax) Upon looking at the docs more, it does say that it would execute regardless if there is an exception or not. So this wouldn't solve the problem I think. *You could attempt to promsify the `Microservice.action(data)` call, and catch it in the try block.* – Evan Bechtol May 13 '19 at 20:48
  • @EvanBechtol could also declare it inside the `try` as `var`. – Patrick Roberts May 13 '19 at 20:58
  • I figured since OP appears to be using ES6 syntax, var would break the style consistency – Evan Bechtol May 13 '19 at 21:00
  • @EvanBechtol if the intention is to initialize the variable inside the `try` and use it after the `catch` if there's no error (would need to return at the end of the `catch` block), then `var` is semantically the best choice since you're intentionally using a function-scope variable instead of a block-scope one. – Patrick Roberts May 13 '19 at 21:02
  • So what do you want it to do with an error in your `MicroService.action(data);`? If you want to ignore any error, (not a good idea),.. then you use another `try / catch` on this action. Try and avoid doing just `try {....} catch () {}`, at least console log the error.. – Keith May 13 '19 at 21:05
  • I’m not arguing that fact by any means. I’m simply saying that based on the code OP shared, ES6 syntax is clearly being used. Which is why I opted for `let` to be more consistent with overall style consistency that OP has already. – Evan Bechtol May 13 '19 at 21:05
  • 1
    Also your subject `How to structure try/catch with async/await?`, the same way you would do it if you wasn't using `async/wait`, and `axios.put` was a synchronous request. – Keith May 13 '19 at 21:11
  • 1
    @PatrickRoberts When I read the question, it didn't seem to be specific about axios at all. When I read your answer, I saw that an axios-specifc solution is the best approach in this case (+1), but the question itself still is a (quite good) duplicate. – Bergi May 13 '19 at 21:54

2 Answers2

2

Avoid vexing exceptions by overriding the validateStatus callback. If a 401 status code is an expected outcome, then treat it like one and allow other unexpected status codes to throw as normal:

const response = await axios.put(url, {}, {
  validateStatus (status) {
    return [200, 401].includes(status);
  }
});

switch (response.status) {
case 200:
  MicroService.action(data);
  break;
case 401:
  MicroService.otherAction(data);
  break;
}

If you don't want any status codes to throw an error, then add a default case to the switch statement:

const response = await axios.put(url, {}, {
  validateStatus () {
    return true;
  }
});

switch (response.status) {
case 200:
  MicroService.action(data);
  break;
case 401:
  MicroService.otherAction(data);
  break;
default:
  console.error(`The server returned an unexpected ${response.status} error upon attempting to hit ${url}`);
  break;
}
Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
0

I can think of two options:

1. If this code is inside a function, you could move the MicroService.action(data) to after the try/catch and put a return in the catch (if applicable to the function).

2. then syntax to call axios:

axios.put(url, {}).then((response) => {
  if (response.status === 200) {
    MicroService.action(data);
  }
}).catch((error) => {
  if (error.status === 401) {
    MicroService.otherAction(data);
  } else {
    console.error(`The server returned an unexpected ${error.status} error upon attempting to hit ${url}`);
  }
});
pdpino
  • 444
  • 4
  • 13