Use Exceptions to Send Error Responses in Jersey

Jersey provides several different ways to send back particular HTTP responses.  While your resource methods can all return Response objects, sometimes it’s more natural to return a domain object if everything goes OK and throw exceptions when errors occur.

The WebApplicationException class serves this purpose.  You throw an instance of it in your resource method, Jersey catches it and sends back the corresponding HTTP response.  While it’s perfectly fine to create & throw WebApplicationException objects, it’s a lot more convenient to create your own subclasses of it for commonly-used responses.

401 Unauthorized

If you have an authentication/authorization system in place to protect access to certain resources, you will become very familiar with the 401 response.  Let’s say we have an Authentication interface and an instance of it can be injected into a resource class:

public interface Authentication
{
    public boolean isAuthenticated(String authorization);
}

One of the first things you’d want to do in a protected resource method is check the user’s credentials, and return a 401 response if necessary:

//this gets injected somehow
private Authentication auth;

@GET
public ImportantThing getImportantThing(@HeaderParam(HttpHeaders.AUTHORIZATION) String authorization)
{
    if (!auth.isAuthenticated(authorization))
        throw new UnauthorizedException();

    ImportantThing thing = ...;
    return thing;
}

This code is very simple and gets the point across to other developers: the method is normally supposed to return an ImportantThing, but in the error case where a user is not properly authorized, an exception is thrown.

Here’s what I use for UnauthorizedException:

import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ws.rs.core.Response.*;

/** Throw this exception to return a 401 Unauthorized response.  The WWW-Authenticate header is
 * set appropriately and a short message is included in the response entity. */
public class UnauthorizedException extends WebApplicationException
{
    private static final long serialVersionUID = 1L;

    public UnauthorizedException()
    {
        this("Please authenticate.", "Name of your web service");
    }

    public UnauthorizedException(String message, String realm)
    {
        super(Response.status(Status.UNAUTHORIZED).header(HttpHeaders.WWW_AUTHENTICATE,
                                                          "Basic realm=\"" + realm + "\"")
                .entity(message).build());
    }
}

409 Conflict

Let’s say in your web service you have a user account resource with URI /users/{username}.  When creating or updating a user by doing a PUT /users/{username} you need to prevent duplicate usernames.  This is a perfect opportunity to return a 409 response.

@PUT
@Path("{username}")
public User createOrUpdateUser(@PathParam("username") String username, @Context UriInfo uriInfo)
{
    if (usernameExists(username))
        throw new ConflictException(uriInfo.getBaseUriBuilder().path("/users/{username}").build(username));

    //create or update the user
    return user;
}

Pretty simple: detect a potential resource conflict and throw an exception.  As a best practice we also include the URI of the conflicting resource in the response.

import java.net.*;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ws.rs.core.Response.*;

/** Thrown to return a 409 Conflict response with optional Location header and entity. */
public class ConflictException extends WebApplicationException
{
    private static final long serialVersionUID = 1L;

    public ConflictException()
    {
        this(null, null);
    }

    public ConflictException(URI location)
    {
        this(location, null);
    }

    public ConflictException(URI location, Object entity)
    {
        super(Response.status(Status.CONFLICT).location(location).entity(entity).build());
    }
}

400 Bad Request

The 400 response is the generic client-side error response.  I typically use it when there are validation errors in parameters submitted to the web service, when creating or updating a resource.  It’s useful to include the error messages in the response body instead of just sending the 400 response.

Let’s continue the user account example.  When creating/updating a user we need to validate a couple things:

  • Email address is properly formed
  • A name is provided

We’ll perform all of the validations and send back a 400 response if any of them fail:

@PUT
@Path("{username}")
public User createOrUpdateUser(@PathParam("username") String username, @FormParam("email") String email, @FormParam("name") String name, @Context UriInfo uriInfo)
{
    if (usernameExists(username))
        throw new ConflictException(uriInfo.getBaseUriBuilder().path("/users/{username}").build(username));

    List<String> errors = new ArrayList<String>();
    if (invalid(email))
        errors.add(email + " is not a valid email address");
    if (empty(name))
        errors.add(name + " must be provided");
    if (!errors.isEmpty())
        throw new BadRequestException(errors);

    //create or update the user
    return user;
}

Here’s the BadRequestException that I use:

import java.util.*;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ws.rs.core.Response.*;

/** Thrown to return a 400 Bad Request response with a list of error messages in the body. */
public class BadRequestException extends WebApplicationException
{
    private static final long serialVersionUID = 1L;
    private List<String> errors;

    public BadRequestException(String... errors)
    {
        this(Arrays.asList(errors));
    }

    public BadRequestException(List<String> errors)
    {
        super(Response.status(Status.BAD_REQUEST).type(MediaType.APPLICATION_XHTML_XML)
                .entity(new GenericEntity<List<String>>(errors)
                {}).build());
        this.errors = errors;
    }

    public List<String> getErrors()
    {
        return errors;
    }
}

Notice that the response entity is a GenericEntity<List<String>> and the response format is XHTML. This lets you create your own MessageBodyWriter for a List that gets formatted in nice XHTML.  You can use a class like this to generate a nicely formatted error response body:

@Provider
@Produces(MediaType.APPLICATION_XHTML_XML)
public class ListStringXhtmlWriter implements MessageBodyWriter<List<String>>

Consider the rest of this class an exercise for the reader (or maybe a future post). 🙂

Advertisements

2 thoughts on “Use Exceptions to Send Error Responses in Jersey

  1. Pingback: Use Exceptions to Send Error Responses in Jersey « Zach's Blog | ServerDemand.Com

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s