Chris' Tech Blog

February 20, 2010

Grails’ REST Client violates HTTP 1.1?

Filed under: Grails — Chris Ey @ 8:50 pm

The goal of this is to build a Grails application that uses a REST servive as a backend.

The REST endpoint is implemented using RESTEasy from the JBoss guys.I have a “create” endpoint, which takes an object of type “Content”, stores it using its own backend and then returns the URI to the newly created object in the HTTP Location header.

The server looks something like this:

@Path("/")
@Produces("application/json")
@Consumes("application/json")
public class RESTEndpoint {

@POST
@Path("/create")
public Response create(Content content, UriInfo uriInfo) {
    Long contentId = contentService.create(content);
    URI newURI = uriInfo.getBaseUriBuilder().path("/content/{key}").build(contentId);
    return Response.created(newURI).build();
}

The point is that the HTTP response produced by this will set the Location header, but it will NOT contain any body. According to HTTP 1.1 this is perfectly legal:

10.2.2 201 Created

   The request has been fulfilled and resulted in a new resource being
   created. The newly created resource can be referenced by the URI(s)
   returned in the entity of the response, with the most specific URI
   for the resource given by a Location header field. The response
   SHOULD include an entity containing a list of resource
   characteristics and location(s) from which the user or user agent can
   choose the one most appropriate.
[...]

So the key phrase is “The response SHOULD include an entity…” but it doesn’t HAVE TO.

But, when we use Grails’ REST client, the following results in an exception from the client:

render withRest(uri: "http://cey-linux:8080/restservice/") {
    def resp = post(path : 'create',
    body: '{ "content":{"name":"My Content"}}"',
    requestContentType: "application/json")
    resp.getHeaders("Location")
}

I don’t have the exception handy but will reproduce and paste it here.

To fix this problem, I now send the URI of the new content object in the Location header and in the body of the response:

    return Response.created(newURI).type(MediaType.TEXT_PLAIN).entity(newURI).build();

This also makes us compatible with HTTP 1.0, which requires that a body is sent in case of response status 201-Created.

3 Comments »

  1. Grails’ REST client doesn’t violate anything. Fundamentally because we don’t ship with a REST client so the REST client you refer to is not Grails’ official one. If you a referring to the Grails REST plugin it may well do, but we (the Grails team) don’t maintain the plugin and a plugin doesn’t necessarily mean Grails itself.

    Comment by Graeme Rocher — February 26, 2010 @ 1:20 am

  2. Right, I am referring to the Rest Client Plugin:
    http://www.grails.org/plugin/rest

    Sorry if I got it confused with Grails’ official code. But wouldn’t it make sense to have an official REST client built in? Or is there any other recommended way to talk to a REST service from within Grails?

    Comment by Chris Ey — February 26, 2010 @ 1:40 am

  3. Filed this problem here:
    http://jira.codehaus.org/browse/GRAILSPLUGINS-1988

    Comment by Chris Ey — February 26, 2010 @ 6:36 pm

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress