Integrating JSend response format with your Web API

Update: This code is now available on GitHub and NuGet!

If you landed on this page than you probably know what JSend is. If you don't than let me enlighten you - JSend is a specification for JSON responses for RESTful APIs. In a nutshell, JSend ensures that your responses look like this:

{
   "data": {
      "yourResource": {
         "id": 1,
         ...
      }
   },
   "message": "Some kind of descriptive message if you have one"
   "status": "success"
}

The data property can contain any relevant data you may want to send back to the client. This could be the actual resource(s) being requested or maybe the list of errors if the request wasn't successful. This is entirely up to your liking.

The message property should contain a descriptive message about the response... that is if you have one. This could be useful when communicating a failure state to the client.

The status property is, well, the status of the response. It can be set to one of these 3:

  1. success - all is good.This is typically your 200 and 300-level HTTP status codes.
  2. fail - client error. This is typically your 400-level HTTP status codes.
  3. error - server error. This is your 500-level HTTP status codes.

There is probably nothing groundbreaking here. In fact, your API likely naturally arrived to a similar format. If it didn't than I'll share a few tricks to get you there :)

First of all, let's create our JSend response object.

[DataContract]
public class JSendApiResonse  
{
    [DataMember(EmitDefaultValue = false)]
    public object Data { get; set; }

    [DataMember(EmitDefaultValue = false)]
    public string Message { get; set; }

    [DataMember]
    public string Status { get; set; }

    public JSendApiResonse(string status, object data = null, string message = null)
    {
        Status = status;
        Data = data;
        Message = message;
    }
}

The general idea is to grab the existing API resource and decorate it with JSendApiResponse. To accomplish this we'll need an ActionFilter.

public class JSendApiResponseActionFilter : ActionFilterAttribute  
{
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        var response = actionExecutedContext.Response;

        if (response != null)
        {
            object content;

            response.TryGetContentValue(out content);

            if (response.IsSuccessStatusCode)
            {
                actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(response.StatusCode, new JSendApiResonse("success", content));
            }
            else
            {
                var error = content as HttpError;

                actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(response.StatusCode, error == null 
                    ? new JSendApiResonse("fail", content, "There was a problem with the request.") 
                    : new JSendApiResonse("fail", error.ModelState, error.Message));
            }
        }

        base.OnActionExecuted(actionExecutedContext);
    }
}

We're almost there. I wanted to be able to throw exceptions from either the API layer or the business layer and have them bubble up to the client as JSend responses. To do this I created a custom exception class.

public class ApiException : Exception  
{
    public ApiException(HttpStatusCode statusCode, string message, Exception ex)
        : base(message, ex)
    {
        StatusCode = statusCode;
    }

    public ApiException(HttpStatusCode statusCode, string message)
        : base(message)
    {
        StatusCode = statusCode;
    }

    public ApiException(HttpStatusCode statusCode)
    {
        StatusCode = statusCode;
    }

    public HttpStatusCode StatusCode { get; }
}

And then an ExceptionActionFilter to intercept and convert these exceptions to JSend responses.

public class ApiExceptionToJSendApiResponseActionFilter : ExceptionFilterAttribute  
{
    public override void OnException(HttpActionExecutedContext context)
    {
        if (context.Exception is ApiException)
        {
            var exception = context.Exception as ApiException;

            context.Response = context.Request.CreateResponse(exception.StatusCode, new JSendApiResonse("fail", null, exception.Message));
        }
        else
        {
            var exception = context.Exception;

#if DEBUG
            var message = string.Format("{0} {1}", exception.Message, exception.StackTrace);
#else

            var message = exception.Message;
#endif

            context.Response = context.Request.CreateResponse(HttpStatusCode.InternalServerError, new JSendApiResonse("error", null, message));
        }
    }

And now we're done. Enjoy your beautiful RESTful responses :)

Update: This code is now available on GitHub and NuGet!