I use a ErrorDecoder to return the right exception rather than a 500 status code.
Is there a way to retrieve the original message inside the decoder. I can see that it is inside the FeignException, but not in the decode method. All I have is the 'status code' and a empty 'reason'.
public class CustomErrorDecoder implements ErrorDecoder {
private final ErrorDecoder errorDecoder = new Default();
@Override
public Exception decode(String s, Response response) {
switch (response.status()) {
case 404:
return new FileNotFoundException("File no found");
case 403:
return new ForbiddenAccessException("Forbidden access");
}
return errorDecoder.decode(s, response);
}
}
Here the original message : "message":"Access to the file forbidden"
feign.FeignException: status 403 reading ProxyMicroserviceFiles#getUserRoot(); content:
{"timestamp":"2018-11-28T17:34:05.235+0000","status":403,"error":"Forbidden","message":"Access to the file forbidden","path":"/root"}
Also I use my FeignClient interface like a RestController so I don't use any other Controler populated with the proxy that could encapsulate the methods calls.
@RestController
@FeignClient(name = "zuul-server")
@RibbonClient(name = "microservice-files")
public interface ProxyMicroserviceFiles {
@GetMapping(value = "microservice-files/root")
Object getUserRoot();
@GetMapping(value = "microservice-files/file/{id}")
Object getFileById(@PathVariable("id") int id);
}
Here is a solution, the message is actually in the response body as a stream.
package com.clientui.exceptions;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.io.CharStreams;
import feign.Response;
import feign.codec.ErrorDecoder;
import lombok.*;
import java.io.*;
public class CustomErrorDecoder implements ErrorDecoder {
private final ErrorDecoder errorDecoder = new Default();
@Override
public Exception decode(String s, Response response) {
String message = null;
Reader reader = null;
try {
reader = response.body().asReader();
//Easy way to read the stream and get a String object
String result = CharStreams.toString(reader);
//use a Jackson ObjectMapper to convert the Json String into a
//Pojo
ObjectMapper mapper = new ObjectMapper();
//just in case you missed an attribute in the Pojo
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
//init the Pojo
ExceptionMessage exceptionMessage = mapper.readValue(result,
ExceptionMessage.class);
message = exceptionMessage.message;
} catch (IOException e) {
e.printStackTrace();
}finally {
//It is the responsibility of the caller to close the stream.
try {
if (reader != null)
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
switch (response.status()) {
case 404:
return new FileNotFoundException(message == null ? "File no found" :
message);
case 403:
return new ForbiddenAccessException(message == null ? "Forbidden
access" : message);
}
return errorDecoder.decode(s, response);
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public static class ExceptionMessage{
private String timestamp;
private int status;
private String error;
private String message;
private String path;
}
}