Custom Reason Phrase in HTTP status error message response with JAX-RS (Jersey)


Codever Logo

(P) Codever is an open source bookmarks and snippets manager for developers & co. See our How To guides to help you get started. Public bookmarks repos on Github ‚≠źūüôŹ


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:

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:

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:

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:

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:

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

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:

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.

Resources

  1. Hypertext Transfer Protocol ‚ÄĒ HTTP/1.1 ‚Äď Response
  2. Jersey User Guide
Subscribe to our newsletter for more code resources and news

Adrian Matei (aka adixchen)

Adrian Matei (aka adixchen)
Life force expressing itself as a coding capable human being

Use test.each in jest to avoid repetitive tests

This blog post makes a case for using jest test.each wherever possible, by refactoring an existing test, thus making the code more concise and maintainable and reduce code duplication Continue reading