Implementing a simple IHttpActionResult

I've recently started a new project which uses Microsoft's Web API framework to create a RESTful version of our product's API. We chose Web API because the team were familiar with it and it's quick and easy to get up and running. However, as with other Microsoft frameworks, things can get more complicated than they seemingly need to be when you try and move away from the simple "Hello, World" type examples on MSDN.

I ran into one of these situations when I wanted to respond to a request with a status code other than 200 and include a message body. In this post I will explain the scenario, the available options and the solution I eventually arrived at.

The scenario

In my scenario I have a controller that accepts a POST to create a new record in the system.

POST /api/widgets
{
  "name": "My Widget",
  "code": "WIDGET",
  "price": -10,
  "stock": 150
}

If there are validation errors I want to be able to reply to the client with a suitable status code (i.e. 400) and a message detailing the errors.

400 
[
 { "property": "code", "message": "A widget with this code already exists." },
 { "property": "price", "message": "Price must be zero or greater." }
]

So far, so simple.

What are the available options?

The ApiController that I inherit from gives me three methods for returning an HTTP 400 response to the client:

There is no HTTP 400 equivalent of Ok<T>(T) which allows me to include an object representing the message body that I can find. Ideally I want to be able to do something like this:

  var errors = this.CreateErrorMessage(...);
  var result = this.BadRequest(errors);

  return result;

I had a look through the System.Web.Http.Results namespace to see if there was an implementation of IHttpActionResult that I could instantiate and return instead, but there did not seem to be. So I decided to implement one myself.

Implementing IHttpActionResult

Implementing IHttpActionResult is fairly straight forward, although that unecessary complexity in Microsoft frameworks that I referred to earlier means that you will need a reference to the HttpRequestMessage for the request.

My implementation of a simple result type which allows you to respond with any status code and an object representing the message body is shown below.

    public class SimpleResult : IHttpActionResult {

        private readonly HttpRequestMessage _request;
        private readonly HttpStatusCode _statusCode;

        public SimpleResult(HttpRequestMessage request, HttpStatusCode statusCode) {
            _request = request;
            _statusCode = statusCode;
        }

        protected HttpRequestMessage Request { get { return _request; } }
        public HttpStatusCode StatusCode { get { return _statusCode; } }

        protected virtual HttpResponseMessage CreateResponse() {
            return _request.CreateResponse(_statusCode);
        }

        #region IHttpActionResult Members

        public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken) {
            return Task.FromResult(
                this.CreateResponse()
            );
        }

        #endregion
    }

    public class SimpleResult<T> : SimpleResult {

        private readonly T _message;

        public SimpleResult(HttpRequestMessage request, HttpStatusCode statusCode, T message) 
            : base(request, statusCode) {
                _message = message;
        }

        public T Message { get { return _message; } }

        protected override HttpResponseMessage CreateResponse() {
            return (_message == null)
                ? this.Request.CreateResponse(this.StatusCode)
                : this.Request.CreateResponse(this.StatusCode, _message);
        }
    }

This means we can now tweak the code above to return HTTP 400 and our validation errors:

  var errors = this.CreateErrorMessage(...);
  var result = new SimpleResult<ErrorReport>(this.Request, HttpStatusCode.BadRequest, errors);

  return result;

Thoughts

Although the final implementation of SimpleResult<T> is, well, simple it did make me wonder about a few things.

Firstly why are the methods on ApiController so specific; why is there no generic CreateResult<T>(HttpStatusCode, T content) method? I can't imagine that Microsoft thought that the available methods would cover all usage scenarios. It seems like an odd omission for a framework geared towards making things as easy as possible.

Secondly why is IHttpActionResult apparently responsible for content negotiation? The HttpResponseMessage indirectly returned by IHttpActionResult represents the low level HTTP response sent back to the client, with an instance of HttpContent representing the serialised message body. There are various subclasses of HttpContent that allow you to return strings etc., but if you want to include an object representing the message body then you also have to provide a formatter. (Thankfully helper methods on HttpRequestMessage will do this for you, but that then means that your result needs a reference to the original HttpRequestMessage.) Mixing low level functionality like content negotiation into high level types like controllers and their results feels like a violation of separation of concerns. OpenRasta's pipeline model is a good example of how proper separation of concerns leads to cleaner and more maintainable code that is easier to work with.

I find that with a lot of Microsoft frameworks a lot of effort is put into making it as quick and easy as possible to get up and running but they occasionally drop the ball when it comes to making it easy to extend or customise. Having said all that I think that Web API is a very good framework and I'm enjoying using it.

Comments