An Opinionated Guide to Handling Errors in Your Rest API: Exceptions

James Louie
Pragmatic Programming
4 min readApr 3, 2020

--

In this article we will cover how what are types of errors that occur in Rest APIs, how we can translate to programming languages, and some general guidelines for how to use exceptions.

Classification of Errors

Let’s start the conversation by describing the classifications of errors the APIs typically experience:

  • Business Errors — Errors caused by expected cases.
  • System Errors — Errors caused by unexpected cases.

Business Errors are caused when the program cannot continue execution due to some expected error state. This can include validation errors, or some other case where business logic indicates the flow cannot continue.

System Errors are caused by issues related to unexpected cases in the code. This may be caused by unexpected errors, or unexpected system state.

It is important for us to be able to distinguish between the two types of errors, as it gives us the foundation for further discussions.

Exceptions

Now that we have classifications for the errors, we can start to write translate that to programming language. Many languages communicate errors through the use of exceptions. Let’s see how we can map these errors to exceptions.

When we are working with errors that we know will occur (ie when we throw the exception), we should allows throw a base BusinessException. There are several examples for how to get more granularity, such as extending this exception for custom exceptions or by extending base Exception class to include “error codes”. Personally I would prefer to extend the Exception class to include error code because that segues into human readable responses when return them to the caller.

You may want to include other default exceptions into the same category as BusinessException. For example NullArgumentException is a common type of error, where it makes sense for you to continue to use it. I would advise to keep the number of exceptions such as this to a minimum, because maintaining a large number of exceptions can be burdensome, and it doesn’t give much value when talking about Rest APIs.

All other exceptions will fall under the System Error case. This could be DbException, ConcurrentException, or any other uncaught exception. These types of exceptions can get bubbled up to the caller framework without being handled. This is not to say they can be handled and/or converted into BusinessExceptions.

When to Use Exceptions

Knowing when to throw an exception is a heavily discussed topic among developers. My stance is that you should try to use other language constructs to describe situations before relying on exceptions. Using exceptions should be a last resort where there is a genuine error and the program cannot continue, or you need to pass more information to the caller than method definition provides.

For example one of the most common cases where an exception should not be used is when the caller is requesting a DB entry which does not exist. We can return either null or optional value as the result instead of throwing an error.

This is not a clear rule, and you should evaluate your use cases for the best approach. For example if you were expecting a DB entry to be created, and it was not, that would be an exception.

Error Propagation

With an understanding of what types of exceptions are API may handle, let’s chat about how to deal with these exceptions.

Rule 1: Do not catch exceptions that you do not handle.

Also known as “swallowing exceptions”, this means that you catch an exception and do nothing with it. Let the exception bubble up until it can be handled or it needs to leave the service boundary into an external system.

Rule 2: Do not the log exception and rethrow.

Honestly this is really just Rule 1, but it is such a big offender that it needs it’s own rule. Let the handler deal with logging the appropriate message.

Rule 3: Catch most specific exception possible

When you do decide to catch an exception, catch the most specific exception possible. This will reduce the likelihood that you might handle the wrong exception thrown.

Rule 4: Do not use exceptions to control flow

Exceptions should not be used to control the flow of your program. This is because typically languages do not optimize for this type of branching, and there is some performance penalty for compiling information needed to create the exception

Rule 5: Keep original cause of the exception

There may be a case where you want to transform an exception into another one. You should always keep the original exception so that you have a reference point of where the exception was thrown.

Further Discussion

In this article we discussed two types of errors that occur in Rest APIs, Business and System errors. We used this to talk about how we should treat the two classifications differently in our code. And then we gave some guidelines for how to exceptions should traverse through your application. In the next part of this series we will talk about how to communicate an program error state to the outside world.

For further reading,

--

--

James Louie
Pragmatic Programming

Developer looking to make the code a little more clean