I have multiple feign clients in a Spring Boot application. I am using a Controller Advice for handling custom exceptions for each feign client.
Here my controller advice that handles two custom exceptions (one for each client: client1 and client2):
@ControllerAdvice
public class ExceptionTranslator implements ProblemHandling {
@ExceptionHandler
public ResponseEntity<Problem> handleCustomClient1Exception(CustomException1 ex, NativeWebRequest request) {
Problem problem = Problem.builder()
.title(ex.getTitle())
.detail(ex.getMessage())
.status(ex.getStatusType())
.code(ex.getCode())
.build();
return create(ex, problem, request);
}
@ExceptionHandler
public ResponseEntity<Problem> handleCustomClient2Exception(CustomException2 ex, NativeWebRequest request) {
Problem problem = Problem.builder()
.title(ex.getTitle())
.detail(ex.getMessage())
.status(ex.getStatusType())
.code(ex.getCode())
.build();
return create(ex, problem, request);
}
}
I have implemented an error decoder for feign client1.
public class ClientErrorDecoder implements ErrorDecoder {
final ObjectMapper mapper;
public ClientErrorDecoder() {
this.mapper = new ObjectMapper();
}
@Override
public Exception decode(String methodKey, Response response) {
ExceptionDTO exceptionDTO;
try {
exceptionDTO = mapper.readValue(response.body().asInputStream(), ExceptionDTO.class);
} catch (IOException e) {
throw new RuntimeException("Failed to process response body.", e);
}
return new CustomException1(exceptionDTO.getDetail(), exceptionDTO.getCode(), exceptionDTO.getTitle(), exceptionDTO.getStatus());
}
}
I have also configured feign for using that error decoder for that specific client like this:
feign:
client:
config:
client1:
errorDecoder: feign.codec.ErrorDecoder.Default
My question is: what is the best approach for handling more than one feign client exceptions? Should I use the same error decoder and treat their responses as a generic exception? Or should I create an error decoder for each feign client?
Error Decoder for Feign client You can use error-decoder to act based on the erroneous HTTP responses. I have observed that error-decoder does not get triggered on success scenarios. To implement an error-decoder, you need to implement a class using ErrorDecoder interface and add that in the configuration.
Let's implement the Feign in our project and invoke other microservices using Feign. Step 1: Select currency-conversion-service project. Step 2: Open the pom. xml and add the Feign dependency.
public class RetryableException extends FeignException. This exception is raised when the Response is deemed to be retryable, typically via an ErrorDecoder when the status is 503.
Quick Answer
If you work with different APIs, error responses will not be formatted the same way. Hence handling them separately seems to be the best approach.
Remarks
From your example, it seems like you defined a custom ErrorDecoder
that may
be not used because you also configured feign to use default error decoder for you client1 in properties file.
Even if you defined a @Configuration
class somewhere with a bean for your custom ClientErrorDecoder
,
Spring Cloud documentation mentions that configuration properties take precedence over @Configuration
annotation
If we create both @Configuration bean and configuration properties, configuration properties will win. It will override @Configuration values. But if you want to change the priority to @Configuration, you can change feign.client.default-to-properties to false.
Example
Here is a hypothetical pruned configuration to handle multiple feign clients with different error decoders :
Client1:
You tell feign to load beans defined in CustomFeignConfiguration
class for client1
@FeignClient(name = "client1", configuration = {CustomFeignConfiguration.class})
public interface Client1 {...}
Client2:
Client2 will use default Feign ErrorDecoder
because no configuration is specified. (Will throw a FeignException
on error)
@FeignClient(name = "client2")
public interface Client2 {...}
Configuration: Be carefull here, if you add @Configuration
to CustomFeignConfiguration
, then ClientErrorDecoder
bean will be used for every loaded feign clients (depending on your application component scanning behaviour)
public class CustomFeignConfiguration {
@Bean
public ClientErrorDecoder clientErrorDecoder(ObjectMapper objectMapper) {
return new ClientErrorDecoder(objectMapper);
}
}
This configuration could be done with properties file aswell.
Side remark
From my point of view, you don't even need controller advice. If you use Spring Web @ResponseStatus
annotation, you can tell which HTTP status code should be sent back with exception body thrown by your custom ErrorDecoder
.
Helpeful resources
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With