Custom Reason Phrase in HTTP status error message response with JAX-RS (Jersey)
In some of my recent work I got the request to produce a custom Reason Phrase in the HTTP status response delivered to one of our REST API consuming clients when an error occurs. In this post I will demonstrate how you can achieve that with Jersey.
1. Define checked exception and exception mapper
As you might have found out from my post Error handling in REST API with Jersey, I like handling the checked exceptions using Jersey’s ExceptionMapper capability.
For the purpose of this demonstration I defined a CustomReasonPhraseException
:
CustomReasonPhraseException
package org.codingpedia.demo.rest.errorhandling; public class CustomReasonPhraseException extends Exception { private static final long serialVersionUID = -271582074543512905L; private final int businessCode; public CustomReasonPhraseException(int businessCode, String message) { super(message); this.businessCode = businessCode; } public int getBusinessCode() { return businessCode; } }
and a CustomReasonPhraseExceptionMapper
to handle the mapping to a response if a CustomReasonPhraseException
occurs:
CustomReasonPhraseExceptionMapper
package org.codingpedia.demo.rest.errorhandling; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import javax.ws.rs.ext.ExceptionMapper; import javax.ws.rs.ext.Provider; @Provider public class CustomReasonPhraseExceptionMapper implements ExceptionMapper<CustomReasonPhraseException> { public Response toResponse(CustomReasonPhraseException bex) { return Response.status(new CustomReasonPhraseExceptionStatusType(Status.BAD_REQUEST)) .entity("Custom Reason Phrase exception occured : " + bex.getMessage()) .build(); } }
Reminder: When the application throws a CustomReasonPhraseException
the toResponse
method of the CustomReasonPhraseExceptionMapper
instance will be invoked.
In the ExceptionMapper
code note line 12:
CustomReasonPhraseExceptionStatusType
return Response.status(new CustomReasonPhraseExceptionStatusType(Status.BAD_REQUEST))
In Jersey’s ResponseBuilder
you have the possibility to define your own status types, by implementing the javax.ws.rs.core.Response.StatusType
interface.
2. Implement custom StatusType
To make a little more extensible I’ve created an AbstractStatusType
class:
AbstractStatusType
package org.codingpedia.demo.rest.errorhandling; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.Response.Status.Family; import javax.ws.rs.core.Response.StatusType; /** * Class used to provide custom StatusTypes, especially for the the Reason Phrase that appears in the HTTP Status Response */ public abstract class AbstractStatusType implements StatusType { public AbstractStatusType(final Family family, final int statusCode, final String reasonPhrase) { super(); this.family = family; this.statusCode = statusCode; this.reasonPhrase = reasonPhrase; } protected AbstractStatusType(final Status status, final String reasonPhrase) { this(status.getFamily(), status.getStatusCode(), reasonPhrase); } @Override public Family getFamily() { return family; } @Override public String getReasonPhrase() { return reasonPhrase; } @Override public int getStatusCode() { return statusCode; } private final Family family; private final int statusCode; private final String reasonPhrase; }
which I extend afterwards with the CustomReasonPhraseExceptionStatusType
to provide the custom Reason Phrase
I desire (e.g. “Custom error message”) in the response:
CustomReasonPhraseExceptionStatusType extends AbstractStatusType
package org.codingpedia.demo.rest.errorhandling; import javax.ws.rs.core.Response.Status; /** * Implementation of StatusType for CustomReasonPhraseException. * The Reason Phrase is set in this case to "Custom error message" */ public class CustomReasonPhraseExceptionStatusType extends AbstractStatusType{ private static final String CUSTOM_EXCEPTION_REASON_PHRASE = "Custom error message"; public CustomReasonPhraseExceptionStatusType(Status httpStatus) { super(httpStatus, CUSTOM_EXCEPTION_REASON_PHRASE); } }
3. Test the custom Reason Phrase in the HTTP status response
3.1. Request
Request example
GET http://localhost:8888/demo-rest-jersey-spring/mocked-custom-reason-phrase-exception HTTP/1.1 Accept-Encoding: gzip,deflate Host: localhost:8888 Connection: Keep-Alive User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
3.2. Response
Et voila:
Response example
HTTP/1.1 400 Custom error message Content-Type: text/plain Content-Length: 95 Server: Jetty(9.0.7.v20131107) Custom Reason Phrase exception occured : message attached to the Custom Reason Phrase Exception
the custom Reason Phrase appears in the response as expected.
Tip: If you want really learn how to design and implement REST API in Java read the following Tutorial – REST API design and implementation in Java with Jersey and Spring
Summary
You’ve seen in this post how to create a custom Reason Phrase in a HTTP status response when you want to flag a “special” error. Of course you can use this mechanism to define your own Reason Phrase-s for other HTTP statuses as well. Actually you should not abuse this Reason Phrase feature as in the HTTP 1.1 rfc2616 is stated the following:
“The Status-Code element is a 3-digit integer result code of the attempt to understand and satisfy the request. These codes are fully defined in section 10. The Reason-Phrase is intended to give a short textual description of the Status-Code. The Status-Code is intended for use by automata and the Reason-Phrase is intended for the human user. The client is not required to examine or display the Reason- Phrase.”[1]
Well, that’s it. Keep on coding and keep on sharing coding knowledge.
Reference: | Custom Reason Phrase in HTTP status error message response with JAX-RS (Jersey) from our JCG partner Adrian Matei at the Codingpedia.org blog. |
Note that this will *not* work for status 400 getReasonPhrase” in jersey code.
I would have found it nice to send a ‘201 Created’ custom mesage with for instance an id of what is created… but apparently it doesn’t suite the web standards.