Override the HTTP Request Method in Jersey
RESTful web services take advantage of all of the HTTP methods including GET, POST, PUT, DELETE, HEAD and OPTIONS. However, a lot of HTTP libraries (BlackBerry JDE, iPhone SDK, etc) and all browsers only support GET and POST. There are several ways to get around these deficiencies – in this post I’ll describe two of them and show a Jersey filter for implementing them.
Jersey provides a PostReplaceFilter that looks for the X-HTTP-Method-Override header and changes the request’s method to that header’s value. To use this approach to perform a PUT from your client, just do a POST request and include a “X-HTTP-Method-Override: PUT” header. The filter will then translate it into a PUT request before handling it.
Ruby on Rails looks for a _method form parameter and changes the request’s method to that parameter’s value. To use this approach to perform a PUT from your client, just do a POST request and include a “_method=PUT” form parameter. The Rails version is particularly useful if you’re making the request from an HTML form (updating or deleting a resource, for example).
I combined the two HTTP method overwriting approaches into a new Jersey filter:
import com.sun.jersey.spi.container.*;
/** Clients may override the HTTP method by setting either the X-HTTP-Method-Override header or
* the _method form or query parameter in a POST request. If both the X-HTTP-Method-Override
* header and _method parameter are present in the request then the X-HTTP-Method-Override header
* will be used.
*
* Inspired by https://jersey.dev.java.net/nonav/apidocs/1.1.0-ea/jersey/com/sun/jersey/api/container/filter/PostReplaceFilter.html
*/
public class OverrideHttpMethodFilter implements ContainerRequestFilter
{
private static final String HEADER = "X-HTTP-Method-Override";
/** The name of the form or query parameter that overrides the HTTP method. */
public static final String METHOD = "_method";
@Override
public ContainerRequest filter(ContainerRequest request)
{
if (request.getMethod().equalsIgnoreCase("POST"))
if (!override(request.getRequestHeaders().getFirst(HEADER), request))
if (!override(request.getFormParameters().getFirst(METHOD), request))
override(request.getQueryParameters().getFirst(METHOD), request);
return request;
}
private boolean override(String method, ContainerRequest request)
{
if (!Strings.isEmpty(method))
{
request.setMethod(method);
return true;
}
return false;
}
}
If you’re creating a web service that uses more than just GET and POST, combining these two approaches will make the unfortunate developers who have to use these flawed HTTP libraries very happy!
Hi,
I found this really useful, but I had to put in a couple of alterations to get it working…
line 29 I changed to if(null!=method && !method.isEmpty())
and line 31 had to be changed to request.setMethod(method.toUppercase());
without those changes, I was getting apparently random failures, but with them it appears to be working well.
Thanks for sharing the original.
Dan
March 18, 2010 at 3:29 pm
Thanks for this, it was a big help!
Mike C
November 23, 2010 at 3:50 am