Kotlin in the backend, Spring with Kotlin Part 2 — Exception Handling

Rodrigo Silva
5 min readMar 30, 2021

Handling exceptions is a crucial part when developing any sort of application, certain errors occur by calling a method of a library with invalid arguments, others happen just for doing something wrong. However, some exceptions can be thrown by ourselves because what was asked to be done by us is not possible.

In the previous post, we developed a simple Web API using Kotlin and Spring, this API allowed us to request and alter information about books in our system, however, when errors are thrown, the information sent to the API client is not the clearest, who becomes unaware of what really went wrong.

Looking at Figure 1, we can see that there are multiple times when exceptions are thrown, these are:

  • Get Specific Book — When the book with the provided ISBN is not in the system;
  • Create Book — When a book with the provided ISBN is already in the system.
Figure 1 — BookService

This information should go to the API’s client in the best way possible, the client should know that an error occurred and what made the error appear.

Figure 2 and 3 shows what is presented to the API’s client when a client tries to obtain a book with an ISBN that is not in the system, and when trying to create a book that’s already registered.

Figure 2 — Get Book that is not in the System
Figure 3 — Create Book that is already in the System

As you can see, we cannot identify what sort of error our request generated, this is not a good way to display errors to the API’s client.

What we will see next is how we can provide more specific errors and how we can define them in our code in an intuitive way.

Exception Handling in Spring MVC

Spring provides multiple ways to handle exceptions, my usual approach is using @ControllerAdvice together with @ExceptionHandler.

The best approach to handling exceptions more specifically is defining a class to represent each exception case, in our example, we can define two classes: NoSuchBookException and BookAlreadyExistsException. So let’s start with that.

First, we’ll define NoSuchBookException which takes as a constructor argument the ISBN of the book

Figure 4 — NoSuchBookException

Now to define BookAlreadyExistsException , this won’t take any constructor arguments for now since the client is providing the book identifier (ISBN) in the request body, so he knows that the Book that already exists is the one with that same ISBN.

Figure 5 — BookAlreadyExistsException

After defining these classes, we must change our BookService class so that instead of throwing an exception with a String message, we’ll just throw one of the exceptions that we defined moments ago.

Figure 6 — BookService

Now that our BookService has been modified we must define a separate class in which we’ll write the code to handle the exception thrown by our API.

We’ll start by creating the BooksExceptionHandler class, which is where we’ll handle the errors that have to do with the Book entity.

We’ll add the appropriate annotation(@ControllerAdvice) to this class, and add a method to handle each type of exception.

Figure 7 — BookExceptionsHandler Class

To represent an error we created a specific class, called ErrorResponseEntity, which receives a title and a detailed message. We can create error representations using the createErrorResponseEntity method which receives the respective error HTTP code and an instance of ErrorResponseEntity .

Figure 8 — ErrorResponseEntity Class

Let’s reproduce the same errors as before what see what our Web API returns to the client.

Figure 9 — Get Book that is not in the System

As you can see, when searching for a book that is not in the system, we get an HTTP error code of 404 (Not Found) and an error JSON object which can tell us more about the error.

Now let’s see what happens when we create the same book twice

Figure 10 — Create Book that is already in the System

When creating the same book twice we get an HTTP error code of 400 (Bad request) because we’re trying to create a book with the same ISBN as a book that’s already in the system. We also get a more detailed error JSON object.

With these changes, we handled the exception which was thrown by our code, of course, we should also handle exception which can happen by code that’s not developed by us.

Final considerations

Handling exceptions can be quite tiresome, however, this can help us improve the client experience when using our API, allowing them to understand specific errors, what caused them, and what they did wrong.

This blogpost in spring.io is great to see different ways of handling exceptions.

https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc

I hope you are enjoying this series of posts about Kotlin in the backend.

My social media info:

--

--