Building Reactive REST APIs with Spring boot 3.2.0 part IV — Final

This last part is a continuation of the previous part III.

Timz Owen
5 min readDec 23, 2023

In this chapter we get to handle on final important topic, exception handling. Exception handling in Spring Boot is an essential aspect of building robust and maintainable applications. Spring Boot provides various mechanisms to handle exceptions gracefully. in the article we get to see an overview of how you can handle exceptions in a Spring Boot application.

Controller Advice:

  • Use @ControllerAdvice to define global exception handling for your controllers. This allows you to centralize exception handling logic.
  • Annotate a class with @ControllerAdvice and define methods annotated with @ExceptionHandler to handle specific exceptions.
@ControllerAdvice
public class GlobalExceptionHandler {

@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("An error occurred: " + e.getMessage());
}

// Add more @ExceptionHandler methods for specific exceptions if needed
}

Custom Exception Classes:

  • Create custom exception classes that extend from RuntimeException or its subclasses.
  • Use these custom exceptions in your application and catch them at appropriate levels.
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}

ResponseEntityExceptionHandler:

  • Extend ResponseEntityExceptionHandler to provide a custom exception handling mechanism for Spring MVC RESTful services.
@ControllerAdvice
public class CustomResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {

@ExceptionHandler(CustomNotFoundException.class)
public ResponseEntity<String> handleNotFoundException(CustomNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage());
}
}

Default Error Handling:

  • Spring Boot provides default error handling that returns a JSON response with error details. You can customize this behaviour by providing your own error properties in the application.properties or application.yml file.
server.error.include-stacktrace=never

In today’s implementation, we focus on Custom exception.

In your project, create a new package. — ‘exception’ and a new java class inside the package — ‘ResourceNotFoundException’. This class extendsRuntimeException’.

public class ResourceNotFoundException extends RuntimeException{
}

Use the @ResponseStatus annotation to declare the HTTP response status code that should be returned when a particular exception is thrown. This annotation allows you to customize the HTTP status code associated with an exception, providing more control over the response status.

Add a value as a parameter to the annotation — ‘NOT Found’ which will be returned to the client. define a Resource exception constructor with a parameter of string message which will be return in every exception using this class.

   // constructor
public ResourceNotFoundException(String message){
super(message);
}

Now, let’s do a little clean up on @Autowiring. This way of performing dependency injection is not recommended. Let’s use constructor injection.

Dependency injection with @Autowired happens at runtime, and potential issues with missing dependencies might not be caught until runtime. Constructor injection allows for compile-time checking.

Remove the @RequiredArgs annotation and @Autowire annotations in Student Service Impl class.

Define a constructor in Impl class that takes the required Student Repository as parameters. Also make the student Repository final.

   //constructor injection
public StudentServiceImpl(StudentRepository studentRepository){
this.studentRepository=studentRepository;
}

Run your application to make sure all still works ok. keep tasting the APIs as shown in the previous chapter.

Catch errors using the new Resource Class.

Point to NOTE: In reactive programming, operations on publishers (such as Mono or Flux) are generally lazy, and they only get executed when someone subscribes to them. If you want to handle the completion or result of the deletion operation, you can use the subscribe method or utilize operators like then to perform subsequent operations.

The ResourceNotFoundException is a custom exception extending RuntimeException.

In the findStudentById method, we use the switchIfEmpty operator to handle the case where the Mono returned by findById is empty (no student found). When the Mono is empty, we use Mono.error to throw an instance of ResourceNotFoundException. add the following code to your existing findbyId method.

.switchIfEmpty(Mono.error(new ResourceNotFoundException("student not found with Id: " + id)));

Task: implement the same thig for delete student by Id.

The then operator is used to execute the delete operation and then proceed with the next operation, which is creating a Mono with the success message.

The switchIfEmpty operator is used to handle the case where no student is found with the specified ID.

The block method is used at the end to block and get the result. However, using block is generally discouraged in reactive programming because it can lead to blocking behaviour. In a real application, you might want to return a Mono<String> or handle the result reactively in some other way.

Delete All

  // CAUTION!! This deletes all records in the database
@Override
public void deleteAll() {
studentRepository.deleteAll()
.then(Mono.just("All data deleted"))
.subscribe();
}

Finally. Handle student update details

  • The switchIfEmpty operator is used to handle the case when the findById operation does not find a student with the specified ID.
  • If the student is not found, the Mono.error method is used to create a ResourceNotFoundException and propagate it downstream.
  • If the student is found, the flatMap operator is used to update the student's values and save the changes.

This marks the end of Building Reactive CRUD Apis with spring boot. you can catch up from part I here.

Thank you for taking the time to explore the world of Spring Boot Reactive APIs on my article! Navigating the intricacies of reactive programming and understanding the principles behind building responsive and scalable applications can be both challenging and rewarding.

I appreciate your curiosity and commitment to staying informed about cutting-edge technologies. Your engagement and interest are crucial drivers for the tech community, and I’m grateful for your readership. Happy coding!

Regards…. Timz Owen #SRE Champion! — Not afraid of chaos!

--

--

Timz Owen

Full stack SRE | DevOps | Automation Engineer. I Love building Tech communities @Africa