Spring WebFlux — Error Handling

black smartphone on table
Reading Time: 3 minutes

Introduction

In this Blog, we’ll take a look at the Spring WebFlux Error Handling using @ControllerAdvice. While calling the services/micro-services anything could go wrong and result in 500 “Internal Server Errors as shown below error:

{
    "timestamp": "2022-09-09T03:42:10.982+00:00",

    "path": "/employee/all",

    "status": 500,

    "error": "Internal Server Error",

    "requestId": "3101b004-1"
}

Usually, error messages like this will not be handled properly and would be propagated to all the downstream services which might impact the user experience. In some cases, applications might want to use application-specific error codes to convey appropriate messages to the calling service.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" 

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 

https://maven.apache.org/xsd/maven-4.0.0.xsd">

   <modelVersion>4.0.0</modelVersion>

   <parent>

      <groupId>org.springframework.boot</groupId>

      <artifactId>spring-boot-starter-parent</artifactId>

      <version>2.6.3</version>

      <relativePath/> <!-- lookup parent from repository -->

   </parent>

   <groupId>com.example</groupId>

   <artifactId>error-handling</artifactId>

   <version>0.0.1-SNAPSHOT</version>

   <name>error-handling</name>

   <description>Demo project for Spring Boot</description>

   <properties>

      <java.version>11</java.version>

   </properties>

   <dependencies>

      <dependency>

         <groupId>org.springframework.boot</groupId>

         <artifactId>spring-boot-starter-webflux</artifactId>

      </dependency>

      <dependency>

         <groupId>org.projectlombok</groupId>

         <artifactId>lombok</artifactId>

         <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>

   <build>

      <plugins>

         <plugin>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-maven-plugin</artifactId>

            <configuration>

               <excludes>

                  <exclude>

                     <groupId>org.projectlombok</groupId>

                     <artifactId>lombok</artifactId>

                  </exclude>

               </excludes>

            </configuration>

         </plugin>

      </plugins>

   </build>

</project>

DTO

First I create a simple DTO for employees. We are interested only in these 3 attributes of employees for now.

Employee.java

Now, I create another class that can respond in case of error.  errorCode can be some app-specific error code and some appropriate error message.

ErrorResponse.java

I also create another exception class as shown here for the service layer to throw an exception when the employee is not found for the given id.

EmployeeNotFoundException.java

Now, Finally, I create a service layer with these 2 methods.

EmployeeService.java

import com.example.errorhandling.dto.Employee;

import com.example.errorhandling.exception.EmployeeNotFoundException;

import org.springframework.stereotype.Service;

import reactor.core.publisher.Flux;

import reactor.core.publisher.Mono;

import java.util.Map;

@Service

public class EmployeeService {

    private static final Map<Integer, Employee> DATA = Map.of(

            1, new Employee(1, "DEEPAK", "KUMAR"),

            2, new Employee(2, "ASHIF", "ALI"),

            3, new Employee(3, "KRISHNA", "JAISHWAL"),

            4, new Employee(4, "HARSH", "GUPTA"),

            5, new Employee(5, "ANKIT", "MOGHA")
    );

    public Flux<Employee> getAllEmployees() {

        return Flux.fromIterable(DATA.values())

                .doFirst(() -> throwRandomError(true));
    }

    private void throwRandomError(boolean flag) {

        if (flag) {
            throw new RuntimeException("Some Errors!!");
        }
    }

    public Mono<Employee> findEmployeeById(int id) {

        return Mono.just(id)

                .filter(e -> DATA.containsKey(e))

                .map(e -> DATA.get(e))

                .switchIfEmpty(Mono.error(() -> new 

EmployeeNotFoundException(id)));

    }
}

To produce an error, I set the value to true, so that we can see the error, and make it false to be able to see the endpoints working.

doFirst(() -> throwRandomError(true));

If I pass the below request, I received the appropriate response instead of directly propagating a 500 Internal Server Error.

http://localhost:8080/employee/28

This error delivered a more meaningful error message. So the calling service using this error code might take appropriate action.

{
   "errorCode":101,

   "message":"Employee id 28 is not found"

}

Similarly, I used the below endpoint (after some time), then the below response get.

http://localhost:8080/employee/all
{
   "errorCode":100,

   "message":"Unable to fetch employees"
}

Conclusion

In this Blog, we learn all about “The error-handling-spring-boot-starter” library is fully ready for Spring WebFlux.

References

https://blog.softwaremill.com/spring-webflux-and-domain-exceptions-10ae2096b159

Written by 

He is a Software Consultant at Knoldus Inc. He has done B.Tech from Dr. APJ Kalam Technical University Uttar-Pradesh. He is passionate about his work and having the knowledge of various programming languages like Java, C++, Python. But he is passionate about Java development and curious to learn Java Technologies. He is always impatient and enthusiastic to learn new things. He is good skills of Critical thinking and problem solving and always enjoy to help others. He likes to play outdoor games like Football, Volleyball, Hockey and Kabaddi. Apart from the technology he likes to read scriptures originating in ancient India like Veda,Upanishad,Geeta etc.

Discover more from Knoldus Blogs

Subscribe now to keep reading and get access to the full archive.

Continue reading