Un servicio RESTful puede fallar por varias razones. En este tutorial, veremos cómo recuperar el mensaje original del cliente de Feign si el servicio REST integrado arroja un error.

Feign es un cliente de servicios web conectable y declarativo que facilita la escritura de clientes de servicios web. Además de las anotaciones de Feign, también es compatible con JAX-RS y admite codificadores y decodificadores para proporcionar una mayor personalización.

Recuperando mensaje de ErrorDecoder

Cuando se producen errores, el cliente de Fingir suprime el mensaje original y, para recuperarlo, necesitamos escribir un ErrorDecoder personalizado. En ausencia de dicha personalización, obtendremos el siguiente error:

feign.FeignException$NotFound: [404] during [POST] to [http://localhost:8080/upload-error-1] [UploadClient#fileUploadError(MultipartFile)]: [{"timestamp":"2022-02-18T13:25:22.083+00:00","status":404,"error":"Not Found","path":"/upload-error-1"}]
	at feign.FeignException.clientErrorStatus(FeignException.java:219) ~[feign-core-11.7.jar:na]
	at feign.FeignException.errorStatus(FeignException.java:194) ~[feign-core-11.7.jar:na]

Para manejar este error, crearemos un bean Java ExceptionMessage simple que represente el mensaje de error:

public class ExceptionMessage {
    private String timestamp;
    private int status;
    private String error;
    private String message;
    private String path;
    // getters y setters standard
}

Recuperemos el mensaje original extrayéndolo en nuestra implementación personalizada de ErrorDecoder:

public class RetreiveMessageErrorDecoder implements ErrorDecoder {
    private ErrorDecoder errorDecoder = new Default();

    @Override
    public Exception decode(String methodKey, Response response) {
        ExceptionMessage message = null;
        try (InputStream bodyIs = response.body()
            .asInputStream()) {
            ObjectMapper mapper = new ObjectMapper();
            message = mapper.readValue(bodyIs, ExceptionMessage.class);
        } catch (IOException e) {
            return new Exception(e.getMessage());
        }
        switch (response.status()) {
        case 400:
            return new BadRequestException(message.getMessage() != null ? message.getMessage() : "Bad Request");
        case 404:
            return new NotFoundException(message.getMessage() != null ? message.getMessage() : "Not found");
        default:
            return errorDecoder.decode(methodKey, response);
        }
    }
}

En nuestra implementación, hemos agregado la lógica basada en posibles errores y, por lo tanto, podemos personalizarlos para cumplir con nuestros requisitos. En el caso predeterminado de nuestro bloque de interruptores, estamos usando la implementación predeterminada de ErrorDecoder.

La implementación predeterminada decodifica la respuesta HTTP cuando el estado no está en el rango 2xx. Cuando throwable se puede volver a intentar, debe ser un subtipo de RetryableException, y debemos generar excepciones específicas de la aplicación siempre que sea posible.

Para configurar nuestro ErrorDecoder personalizado, agregaremos nuestra implementación como un bean en la configuración de Feign:

@Bean
public ErrorDecoder errorDecoder() {
    return new RetreiveMessageErrorDecoder();
}

Ahora, veamos la excepción con el mensaje original:

com.ricardogeek.openfeign.exception.NotFoundException: Page Not found
	at com.ricardogeek.openfeign.fileupload.config.RetreiveMessageErrorDecoder.decode(RetreiveMessageErrorDecoder.java:30) ~[classes/:na]
	at feign.AsyncResponseHandler.handleResponse(AsyncResponseHandler.java:96) ~[feign-core-11.7.jar:na]

Categorized in:

Tagged in:

, , ,