Netflix Feign - Propagate Status and Exception through Microservices

Pau picture Pau · Aug 5, 2016 · Viewed 41.9k times · Source

I'm using Netflix Feign to call to one operation of a Microservice A to other other operation of a Microservice B which validates a code using Spring Boot.

The operation of Microservice B throws an exception in case of the validation has been bad. Then I handled in the Microservices and return a HttpStatus.UNPROCESSABLE_ENTITY (422) like next:

@ExceptionHandler({
       ValidateException.class
    })
    @ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
    @ResponseBody
    public Object validationException(final HttpServletRequest request, final validateException exception) {
        log.error(exception.getMessage(), exception);
        error.setErrorMessage(exception.getMessage());
        error.setErrorCode(exception.getCode().toString());
        return error;
    }

So, when Microservice A calls to B in a interface as next:

@Headers("Content-Type: " + MediaType.APPLICATION_JSON_UTF8_VALUE)
@RequestLine("GET /other")
void otherOperation(@Param("other")  String other );

@Headers("Content-Type: " + MediaType.APPLICATION_JSON_UTF8_VALUE)
@RequestLine("GET /code/validate")
Boolean validate(@Param("prefix") String prefix);

static PromotionClient connect() {

    return Feign.builder()
        .encoder(new GsonEncoder())
        .decoder(new GsonDecoder())
        .target(PromotionClient.class, Urls.SERVICE_URL.toString());
}

and the validations fails it returns a internal error 500 with next message:

{
  "timestamp": "2016-08-05T09:17:49.939+0000",
  "status": 500,
  "error": "Internal Server Error",
  "exception": "feign.FeignException",
  "message": "status 422 reading Client#validate(String); content:\n{\r\n  \"errorCode\" : \"VALIDATION_EXISTS\",\r\n  \"errorMessage\" : \"Code already exists.\"\r\n}",
  "path": "/code/validate"
}

But I need to return the same as the Microservice operation B.

Which would be the best ways or techniques to propagate Status and Exceptions through microservices using Netflix Feign?

Answer

Mathias Dpunkt picture Mathias Dpunkt · Aug 5, 2016

You could use a feign ErrorDecoder

https://github.com/OpenFeign/feign/wiki/Custom-error-handling

Here is an example

public class MyErrorDecoder implements ErrorDecoder {

    private final ErrorDecoder defaultErrorDecoder = new Default();

    @Override
    public Exception decode(String methodKey, Response response) {
        if (response.status() >= 400 && response.status() <= 499) {
            return new MyBadRequestException();
        }
        return defaultErrorDecoder.decode(methodKey, response);
    }

}

For spring to pick up the ErrorDecoder you have to put it on the ApplicationContext:

@Bean
public MyErrorDecoder myErrorDecoder() {
  return new MyErrorDecoder();
}