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.
Thanks for this, it was a big help!
Pingback: PATCH request using Jersey Client | Ngoding