Spring WebFlux Rest API Global Exception Handling
Last Updated :
24 May, 2024
Spring WebFlux is part of Spring Framework, allowing us to Reactive programming and Support non-blocking I/O operations. The Spring Framework provides a lot of Annotations to handle the applications. This article focuses on Global Exception Handling by using Rest API in the Spring WebFlux. For this, we have one Spring Annotation that is @ControllerAdvice This annotation catches the exceptions from the entire module. Also, we can change the type of HTTP status code while dealing with the server by using this @ControllerAdvice annotation.
To achieve the Global exception handling, we need to create a custom Exception Handler class in the project. This class can handle the exceptions globally. Here we use ResponseStatusExceptionHandler interface to override the exception-handling methods with our logic.
Key Features Global Exception Handling:
- Centralized Error Management
- Allows you to manage all exceptions in a single place rather than scattering exception-handling logic throughout your application code.
- Consistent Response Format
- Ensures that all error responses follow a consistent format which improves the API's usability and predictability for clients.
- Custom Exception Handling
- Supports custom exceptions, allowing you to handle specific scenarios like ResourceNotFoundException, BadRequestException.
- Default Exception Handling
- Provides a default handler for unexpected exceptions ensuring that the application does not expose internal details or stack traces in production.
- Integration with Reactive Programming
- Non-blocking and efficient error handling in a reactive web environment.
Prerequisites:
- Spring Framework
- Spring WebFlux
- Error Handling in Spring WebFlux
- Spring Annotations
- Components & Beans in Spring Framework
- Java Programming
Tools & Technologies:
- Spring Tool Suite
- Spring Framework
- Reactive programming
- Maven
Steps to Implement Spring WebFlux Rest API Global Exception Handling
Here we created one simple spring reactive project by using spring initializr. It can able to create Spring Stater Project by using required dependencies. Below we provide the dependencies which are used in this Spring Application.
Dependencies:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Project Structure:
Below is the project structure, after creating the project using Spring Initializr.

Error Handling Responses
- ResourceNotFoundException:
- Status: 404 Not Found
- Message: Resource not found with id: {id}
- BadRequestException:
- Status: 400 Bad Request
- Message: Invalid request to create resource
- Generic Exception:
- Status: 500 Internal Server Error
- Message: An unexpected error occurred: {error message}
Steps 1:
Once project is created with required dependencies, then we created two custom exception classes, which can handle Runtime Exceptions. And we define constructors also in those two custom exception classes to provide meaning full error message to end user while getting error.
ResourceNotFoundException.java:
Java
package com.app;
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
}
BadRequestExceptionjava:
Java
package com.app;
public class BadRequestException extends RuntimeException {
public BadRequestException(String message) {
super(message);
}
}
These two classes are to used to provide meaning full error message to the end user while handling exceptions globally in the Spring Application.
Steps 2:
After that, we created one java class for handling exceptions globally by using @ControllerAdvice spring annotations.
- This class contains information about custom exception classes.
- And here we use @ExceptionHandler annotation It is root exception handler in Spring framework.
- For this annotation we provide custom exception classes as target classes.
- Here we give two different custom exception classes namely ResourceNotFoundException and BadRequestException as target custom exception class to the @ExceptionHandler.
Java
package com.app;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.handler.ResponseStatusExceptionHandler;
import reactor.core.publisher.Mono;
@ControllerAdvice
public class GlobalExceptionHandler extends ResponseStatusExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public Mono<ResponseEntity<String>> handleResourceNotFoundException(ResourceNotFoundException ex, ServerWebExchange exchange) {
return Mono.just(ResponseEntity.status(HttpStatus.NOT_FOUND).body(ex.getMessage()));
}
@ExceptionHandler(BadRequestException.class)
public Mono<ResponseEntity<String>> handleBadRequestException(BadRequestException ex, ServerWebExchange exchange) {
return Mono.just(ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage()));
}
@ExceptionHandler(Exception.class)
public Mono<ResponseEntity<String>> handleGenericException(Exception ex, ServerWebExchange exchange) {
return Mono.just(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("An unexpected error occurred: " + ex.getMessage()));
}
}
In the above class, we handle three different exceptions and converted into required HTTP Status code.
- ResourceNotFoundException - NOT_FOUND
- BadRequestException - BAD_REQUEST
- Exception - INTERNAL_SERVER_ERROR
Steps 3:
Once required logic is completed to handle exceptions globally, Immediately we write logic for creating API endpoints and Router Functions in same same java class by using @Configuration Spring Annotation. For creating Routing end point in WebFlux we use RouterFunction interface in Spring Reactive programming. And This function returns a router.
RouterConfig.java:
Java
package com.app;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
@Configuration
public class RouterConfig {
@Bean
public RouterFunction<ServerResponse> routeFunction() {
return RouterFunctions
.route(RequestPredicates.GET("/resource/{id}"), this::getResource)
.andRoute(RequestPredicates.POST("/resource"), this::createResource)
;
}
public Mono<ServerResponse> getResource(ServerRequest request) {
String id = request.pathVariable("id");
return Mono.error(new ResourceNotFoundException("Resource not found with id: " + id));
}
public Mono<ServerResponse> createResource(ServerRequest request) {
return Mono.error(new BadRequestException("Invalid request to create resource"));
}
private RouterFunction<ServerResponse> errorRoutes() {
return route()
.onError(ResourceNotFoundException.class, this::handleResourceNotFoundException)
.onError(BadRequestException.class, this::handleBadRequestException)
.onError(Exception.class, this::handleGenericException)
.build();
}
private Mono<ServerResponse> handleResourceNotFoundException(Throwable throwable, ServerRequest request) {
return ServerResponse.status(HttpStatus.NOT_FOUND)
.contentType(MediaType.TEXT_PLAIN)
.bodyValue(throwable.getMessage());
}
private Mono<ServerResponse> handleBadRequestException(Throwable throwable, ServerRequest request) {
return ServerResponse.status(HttpStatus.BAD_REQUEST)
.contentType(MediaType.TEXT_PLAIN)
.bodyValue(throwable.getMessage());
}
private Mono<ServerResponse> handleGenericException(Throwable throwable, ServerRequest request) {
return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR)
.contentType(MediaType.TEXT_PLAIN)
.bodyValue("An unexpected error occurred: " + throwable.getMessage());
}
}
In this above class, first we define the Routing End points.
@Bean
public RouterFunction<ServerResponse> routeFunction() {
return RouterFunctions
.route(RequestPredicates.GET("/resource/{id}"), this::getResource)
.andRoute(RequestPredicates.POST("/resource"), this::createResource)
;
}
After this, we created two API endpoints by using GET and POST HTTP request type.
public Mono<ServerResponse> getResource(ServerRequest request) {
String id = request.pathVariable("id");
return Mono.error(new ResourceNotFoundException("Resource not found with id: " + id));
}
public Mono<ServerResponse> createResource(ServerRequest request) {
return Mono.error(new BadRequestException("Invalid request to create resource"));
}
After this, again we created one more Router Function to handle the Exceptions.
private RouterFunction<ServerResponse> errorRoutes() {
return route()
.onError(ResourceNotFoundException.class, this::handleResourceNotFoundException)
.onError(BadRequestException.class, this::handleBadRequestException)
.onError(Exception.class, this::handleGenericException)
.build();
}
After this we created Mono type publishers to to customize the exceptions types into required HTTP codes like 403, 400 and other code.
private Mono<ServerResponse> handleResourceNotFoundException(Throwable throwable, ServerRequest request) {
return ServerResponse.status(HttpStatus.NOT_FOUND)
.contentType(MediaType.TEXT_PLAIN)
.bodyValue(throwable.getMessage());
}
private Mono<ServerResponse> handleBadRequestException(Throwable throwable, ServerRequest request) {
return ServerResponse.status(HttpStatus.BAD_REQUEST)
.contentType(MediaType.TEXT_PLAIN)
.bodyValue(throwable.getMessage());
}
private Mono<ServerResponse> handleGenericException(Throwable throwable, ServerRequest request) {
return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR)
.contentType(MediaType.TEXT_PLAIN)
.bodyValue("An unexpected error occurred: " + throwable.getMessage());
}
Steps 4: Run the Application
Now required logic is completed. Now Run this project as Spring Boot App and this project runs on Netty Server with port number 8080 by default.

Steps 5: Testing the APIs
After running the project, we need test the API endpoints, here we use Post Man tool for testing API endpoints.
getResource API:
http://localhost:8080/resources/101

createResource API:
http://localhost:8080/resources

Advantages of Global exception handling
- Improved Maintainability
- Enhanced Debugging and Logging
- Better Client Communication
- Separation of Concerns
- Scalability
Similar Reads
Spring WebFlux Functional Endpoints CRUD REST API Example
Spring Boot is a Java framework for back-end development. Another miracle in Spring Boot is the Spring Boot Community has developed the Spring Reactive Web Framework i.e. Spring WebFlux. To develop this project, we have used the MongoDB database. Here, for every CRUD (Create, Retrieve, Update, Delet
7 min read
Spring MVC - Exception Handling
Prerequisites: Spring MVC When something goes wrong with your application, the server displays an exception page defining the type of exception, the server-generated exception page is not user-friendly. Spring MVC provides exception handling for your web application to make sure you are sending your
6 min read
Exception Handling in Spring Boot
Exception handling in Spring Boot helps deal with errors and exceptions present in APIs, delivering a robust enterprise application. This article covers various ways in which exceptions can be handled and how to return meaningful error responses to the client in a Spring Boot Project. Key Approaches
8 min read
Handling Errors in Spring WebFlux
The Spring Boot Community Developed the Spring Reactive Web Framework. The SpringReactive allows developers to build asynchronous, non-blocking, and event-driven web applications. When compared with the Spring MVC framework the Spring Reactive Web framework provides more functionality. The Spring We
6 min read
Spring WebFlux Reactive CRUD REST API Example
Spring WebFlux can be defined as the reactive programming framework provided by the Spring ecosystem for the building of asynchronous, non-blocking, and event-driven applications and it can be designed to handle a large number of concurrent connections while consuming less resources. Key Terminologi
5 min read
Custom WebFlux Exceptions in Spring Boot 3
The Spring WebFlux is part of Spring Framework and it allows us for Reactive programming it supports Non Blocking I/O operations. The Spring Framework provides a lot of Annotations to handle the applications. In this article, we focus on Custom WebFlux Exceptions in Spring Boot 3 by using Rest API i
4 min read
Logging in Spring WebFlux
Logging in Spring WebFlux is important for monitoring, debugging, and tracing the flow of requests through the reactive application. Here is how to effectively use logging in a Spring WebFlux application. There are log logger frameworks available in the market to handle logs in the software applicat
5 min read
How to Resolve Spring Webflux DataBufferLimitException?
The DataBufferLimitException in Spring WebFlux typically occurs when the data buffer size exceeds the maximum allowed limit while processing large payloads. This can be encountered when dealing with large request or response bodies. To resolve this exception, we can adjust the buffer limits or handl
5 min read
Rate Limiting in Spring WebFlux
Rate limiting is a crucial technique to control the amount of incoming traffic to the server. This prevents abuse, ensures fair resource usage, and protects against potential Denial of Service (DOS) attacks. In the Spring WebFlux, rate limiting can be implemented effectively using the Spring Cloud G
5 min read
Throwing an Exception vs Mono.error() in Spring WebFlux
In Spring Webflux, reactive programming is embraced, introducing concepts like Mono and Flux for asynchronous data handling. In this article, we will learn the differences between throwing exceptions and using Mono.error() in Spring Webflux. Exceptions and Error Handling in Spring WebfluxExceptions:
3 min read