Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How implement Error decoder for multiple feign clients

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?

like image 731
YanetP1988 Avatar asked May 29 '19 02:05

YanetP1988


People also ask

How do you use feign error decoder?

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.

How do you connect two Microservices using Feign client?

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.

What is feign RetryableException?

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.


1 Answers

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

  • Spring Cloud Documentation
  • GitHub issue related to the subject
like image 99
user3793803 Avatar answered Dec 16 '22 16:12

user3793803