Passing erros throught microsservices (Java + Spring)
Tags: java, spring, exceptions, microservices
Published: 2024-07-11 03:11:10

Hey folks! Here's another quick tip for you: today, we're diving into handling exceptions in Java and how we can smoothly manage errors across microservices (among other approaches). Let's learn together! 👨‍💻🚀


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jn8655etfo8trp8p6w70.png)

Some time ago, I came across an issue where I needed to pass an error to the BFF (Backend-for-frontend). In essence, we have three microservices: one BFF, and others that handle the business logic of the application. Errors triggered within the business logic need to at least return a message to the BFF. This allows the frontend to determine the best error message and the most appropriate way to handle that specific error.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j6x25ptnf9ndo0xwe11i.png)

In short, the approach is quite straightforward: the server sends an error code through a header, and both the frontend and BFF are responsible for reading this code and returning a formatted JSON response to the frontend. Here are the steps:

1. Trigger an exception on the server, passing the error code.
2. The ExceptionHandler handles this exception and inserts the error code into a header called "CODE".
3. On the BFF side, this error is captured and a JSON response is constructed to be sent back to the frontend.

**Here's a rough outline of how the code might look:**

```
@Service
public class ServerService {

    public Sucesso testMethod(Long id) {
        if (id == 1) {
            throw new ServerException(HttpStatus.BAD_REQUEST, ERROR_001);
        } else if (id == 2) {
            throw new ServerException(HttpStatus.BAD_REQUEST, ERROR_002);
        } else if (id == 3) {
            throw new ServerException(HttpStatus.BAD_REQUEST, ERROR_003);
        }
        return Sucesso.builder().id(id).build();
    }
}
```

**Afterward, on the server side, this is the class responsible for handling triggered errors and adding the error code into the respective header!**

```
@RestControllerAdvice
public class ControlExceptionHandler {

    public static final String CODE = "CODE";

    @ExceptionHandler({ServerException.class})
    public ResponseEntity<Object> serverException(ServerException e) {
        HttpHeaders responseHeaders = new HttpHeaders();
        responseHeaders.add(CODE, e.getCode());
        return ResponseEntity.status(e.getHttpStatusCode()).headers(responseHeaders).build();
    }

}

```

**On our BFF side, we use the `.onStatus()` method to check if an error occurred in the request and take appropriate actions (in this case, throwing a `ClientException` based on the obtained response)."**

```
@Service
public class ServerService {

    public static final String CODE = "CODE";
    private final RestClient restClient;

    public ServerService(RestClient restClient) {
        this.restClient = restClient;
    }

    public Sucesso testMethod(Long id) {
        return restClient
                .get()
                .uri("http://localhost:8080?id=" + id)
                .retrieve()
                .onStatus(HttpStatusCode::isError, (HttpRequest request, ClientHttpResponse response) -> {
                    throw new ClientException(HttpStatus.BAD_REQUEST, Objects.requireNonNull(response.getHeaders().get(CODE)).get(0));
                })
                .body(Sucesso.class);
    }
}
```

**And then, still on the BFF side, we construct the response for the Frontend based on the header captured from the response.**

```
@RestControllerAdvice
public class ControlExceptionHandler {

    @ExceptionHandler({ClientException.class})
    public ResponseEntity<Object> ClientException(ClientException e) {
        return ResponseEntity.status(e.getHttpStatusCode()).body(e.getOnlyBody());
    }

}
```

**Finally, this is the result that we expect.**

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tqb7kfyclk3jr6nop60a.png)

---

Here's the code on github: https://github.com/FelipeJansenDev/errors-between-microsservices

Follow me on Linkedin for more tips and tricks: https://www.linkedin.com/in/felipe-neiva-jansen/