Java Full Stack Spring boot & React app: Backend REST API / 4 - Exception handling

Hello, I am a full stack developer since 2010 focused for a long moment more on backend stuffs. I embraced cloud development since 2019.
Search for a command to run...

Hello, I am a full stack developer since 2010 focused for a long moment more on backend stuffs. I embraced cloud development since 2019.
No comments yet. Be the first to comment.
In this series, we'll create a full-stack java project from scratch using Spring boot for backend stuff and react for frontend.
Hello, In this tutorial, we'll set up the backend. What you'll learn here are: How to initialize a Spring boot app using the official Spring boot initializer and How to customize a spring boot app port. Project set up Our backend API will be named...
Security in internet-facing or local applications is one of the most challenging parts of the software development life cycle. This post will provide a quick step-by-step guide to implementing access management for the previous REST API using Amazon ...

In this post, we will create a REST API endpoint with GET and POST methods for the previous backend using Amazon API Gateway's HTTP API. Prerequisites All you need is just an AWS account: no worries, if you are new to AWS, AWS offers you a 12-month f...

In this article, we'll build a simple CRUD JavaScript-based backend with AWS. We'll use Lambda and DynamoDB to show how you can quickly create a secure and robust app backend. Prerequisites To follow this tutorial, you need an AWS account. Thankfully...

There are many articles on how to build a real-world Spring Boot CRUD REST API or Application with MySQL as a Relational Database. In this post, we are not only going to show how to create a Spring Boot CRUD operations API, but we will also dive deep...

Before entering the AWS Cloud world, as a Java developer, it was often difficult for me to get Java-based applications online for my clients. Fortunately, I found out later that AWS provides many proven, fully managed services for deploying Java-bas...

Hello,
In this previous tutorial, we secured our backend RESTful API using Spring Security and JWT. Now we are going to handle errors/exceptions in the RESTful API.
Until now, all eventual error messages thrown in our RESTful API are not user-friendly. For example, when you try to log in with invalid credentials, you should have a similar message in Postman:

In the following lines, we'll use one of the smart solutions Spring provides to make the API throw understandable error messages.
This java class will be the custom error message class to return by the API when an error occurs. Create it in the com.codeurinfo.easytransapi.exception package.
package com.codeurinfo.easytransapi.exception;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDateTime;
import org.springframework.http.HttpStatus;
public class ExceptionResponse {
private HttpStatus status;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss")
private LocalDateTime timestamp;
private String message;
private String description;
public ExceptionResponse() {
this.timestamp = LocalDateTime.now();
}
public ExceptionResponse(HttpStatus status) {
this();
this.status = status;
this.message = "An error occured";
}
public ExceptionResponse(String message) {
this();
this.message = message;
}
public ExceptionResponse(HttpStatus status, String message, Throwable ex) {
this();
this.status = status;
this.message = message;
this.description = ex.getLocalizedMessage();
}
public LocalDateTime getTimestamp() {
return this.timestamp;
}
public void setTimestamp(LocalDateTime timestamp) {
this.timestamp = timestamp;
}
// getters and setters
}
Let's create this class in com.codeurinfo.easytransapi.exception package to handle all the errors in the RESTful API.
package com.codeurinfo.easytransapi.exception;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalControllerExceptionHandler {
@ExceptionHandler({ DataIntegrityViolationException.class })
@ResponseStatus(value = HttpStatus.CONFLICT)
public ExceptionResponse handleDIVException(
DataIntegrityViolationException e
) {
return new ExceptionResponse(
HttpStatus.CONFLICT,
"Data integrity error.",
e
);
}
@ExceptionHandler({ Exception.class })
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public ExceptionResponse handleException(Exception e) {
return new ExceptionResponse(
HttpStatus.INTERNAL_SERVER_ERROR,
e.getLocalizedMessage(),
e
);
}
@ExceptionHandler({ AccessDeniedException.class })
@ResponseStatus(value = HttpStatus.FORBIDDEN)
public ExceptionResponse handleForbiddenException(AccessDeniedException e) {
return new ExceptionResponse(
HttpStatus.FORBIDDEN,
e.getLocalizedMessage(),
e
);
}
}
Spring @RestControllerAdvice annotation is used on a global class to make all its methods annotated with @ExceptionHandler be accessible across all the controllers in the RESTful API.
@ExceptionHandler annotation is used upon methods to handle specific Exceptions.
Thus, we use @ExceptionHandler({ DataIntegrityViolationException.class }) on the handleDIVException method to handle all DataIntegrityViolation Exceptions occurred in @RepositoryRestResource annotated repository interfaces.
@ResponseStatus is used to send the corresponding HTTP status code for the JSON response.
For unknown exceptions handling, we use @ExceptionHandler({ Exception.class }) on the handleException method and provide a HttpStatus.INTERNAL_SERVER_ERROR status code to return.
Similarly, we use @ExceptionHandler({ AccessDeniedException.class }) and provide HttpStatus.FORBIDDEN on the handleForbiddenException method to handle URL access denied exception.
1 - Log in with bad credentials
{
"userName": "user",
"password": "user1"
}

2 - Try to access an unauthorized resource
Suppose you logged in with user/user good credentials, following our API logic, a user with username user is not allowed to make a routeByName search request

In the next post, we'll add new features to our EasyTrans app. Hope you learned something new. If so, don't forget to hit the Like button and subscribe to this blog to be up to date with new posts.