How to deal with 4xx responses in MicroProfile Rest-Client

Heiko W. Rupp
ITNEXT
Published in
3 min readNov 29, 2019

--

The Eclipse MicroProfile Rest-Client is a pretty cool piece of software. I think I even mentioned that before 😀. And one of the cool features is that you don’t have to deal with the low level http handling.

But sometimes you want to actually deal with the nitty gritty of http — notably dealing with different status codes that convey a semantic. The default handling is that for every code ≄ 400, a WebApplicationException is thrown, which just tells you that the call did not succeed, but does not differentiate further.

Custom Exception Mappers to the rescue

Luckily one does not need to resort back to basic HttpClient to solve the challenge, but can use a powerful feature, namely custom ResponseExceptionMappers. Let’s have a look at an example implementation first and then how to apply it to your code. This builds on the code of my previous post.

@Priority(4000)                                            // (1)
public class MyMapper implements
ResponseExceptionMapper<RuntimeException> { // (2)
@Override
public RuntimeException toThrowable(Response response) {
int status = response.getStatus(); // (3)

String msg = getBody(response); // see below

RuntimeException re ;
switch (status) {
case 412: re = new ValidationException(msg); // (4)
break;
default:
re = new WebApplicationException(status); // (5)
}
return re;
}
  1. Tell the rest-client about the priority. If multiple mappers match, the one with the lowest priority is taken
  2. Our class needs to implement the ResponseExceptionMapper interface
  3. We can retrieve the status code from the response
  4. and use it to dispatch to different types of Exceptions
  5. For all other codes we use the default

If the server we are calling is returning a response in the body, we want to know it and also supply it in the exception. This can be achieved the following way:

private String getBody(Response response) {
ByteArrayInputStream is = (ByteArrayInputStream) response.getEntity();
byte[] bytes = new byte[is.available()];
is.read(bytes,0,is.available());
String body = new String(bytes);
return body;
}

Now that we have the mapper functionality, we need to tell the rest client when it should be applied. To do this, we register the mapper to the interfaces we want to use it with:

@RegisterRestClient
@RegisterProvider(value = MyMapper.class,
priority = 50)
public interface VerifyEngine {

Just add a @RegisterProvider annotation on the interface and you are done. If the remote server now responds with code 412, you will get a ValidationException, that you can work with:

@Inject
@RestClient
VerifyEngine engine;
[...]try {
engine.verify(policy);
}
catch (ValidationException ve) {
// Deal with a 412 response
}
catch (Exception e) {
// Deal with other cases
}

More ?

If you want to learn more about Eclipse MicroProfile, have a look at the book “Hands-on Enterprise Java Microservices with Eclipse MicroProfile” where I am also a co-author.

--

--