Wednesday, February 27, 2013

How to return a Location header from a Jersey REST service

If you're following the Resource Oriented architectural style (ROA) for REST you're often interested in building and returning hyperlinks to your resources in your web service responses.

In the case of an HTTP CREATE, in addition to returning an HTTP 201 response code, you're also going to want to return a hyperlink to the newly created resource in the Location header of the response.

The Jersey JSR 311 implementation makes this a trivial task.  The first step, as you can see in line 2 below, is to inject a UriInfo class member using the Jersey @Context annotation.  Jersey recognizes a number of different resources that can be injected into your service classes via the @Context annotation.  In this case we're interested in information about the URI of our web service.

Once you've completed the work of creating your new resource (whatever that happens to be) and you're ready to formulate a response it's a simple matter to create the hyperlink and place it in the Location header of the response.  The key is to get the absolute URI to this current service as we're doing in line 21 below.  And assuming your URI convention is to tack the ID on to the URI for the CREATE service (as it probably should be in REST) simply append the ID to the absolute URI and use the Jersey Response builder to complete your response.

The hyperlink we just created should look something like http://mydomain/services/resource/1234 and map over to the GET-mapped service shown below starting on line 34.

    @Context
    private UriInfo _uriInfo;
  
    @Path("/resource")
    @POST
    public Response createResource(String data) {
        Response response = null;

        try {
            // convert data to model object
            Model model = someConversionMethod(data);
            // save model object
            _businessManager.saveModel(model);

            // formulate the response
            response = Response.status(201)
                .header(
                    "Location",
                    String.format(
                        "%s/%s",
                        _uriInfo.getAbsolutePath().toString(),
                        model.getId()
                    )
                )
                .entity(model.getId())
                .build();
        } catch (Exception e) {
            response = Response.status(500).entity(e.getMessage()).build();
        }

        return response;
    } // createResource()

    @Path("/resource/{id}")
    @GET
    public Response getResource(@PathParam("id") String id) {
        ... 
See this post if you want to learn how to easily test your Jersey REST services.