Published on 2011-06-24 by John Collins. Socials: YouTube - X - Spotify - Amazon Music - Apple Podcast |
I have been doing a lot of thinking recently about adding REST (Representational State Transfer) API support to the Alpha Framework, which is presently on the roadmap but unscheduled. In this article, I will attempt to capture my thought processes on how this will work, and how it will be introduced into the framework with the minimum of impact.
My design goals are as follows:
The controllers in Alpha presently have support for doGET and doPOST methods, which are a requirement of the AlphaControllerInterface. The methods are used to implement the code which will handle GET and POST requests respectively, but typically in a REST based solution you will also handle these additional request types (or verbs):
Presently the Alpha Framework has only one response format: HTML. When I designed the framework, I played with the concept of a viewMode property on each view class which would control the output format used in the response, but I removed this before the 1.0 release of Alpha because I felt that it just added complexity. Given that the REST API will now force this back into scope, I will need to address this requirement as cleanly as possible without impacting on the existing systems using Alpha 1.0.
At a high level, here are the following formats that I would like to target:
This is a lot of work, but my intention is to add the supporting framework first, then add the various output formats one at a time afterwards (with the existing HTML4 standard web pages being upgraded to HTML5 as the first priority, followed closely by the XML REST responses).
But how does the framework know the desired format to return to the client?
Well, there are two approaches here: have a different URL for the different response formats, or use the Accept header set in the request by the header. A lot of APIs are using the first approach, for example the Twitter API uses the concept of a file extension on the URL (even though no actual file is returned), using .json for JSON responses and .xml for XML responses. My understanding of REST however is that the aim is to have a single URL per resource, and for me using a file extension or other URL parameter violates this.
The Accept header seems like a neater approach to, which is often termed content negotiation. If the client wants the XML or JSON responses, it should set one of the following headers on its request:
Accept: application/xml Accept: application/json
To keep things simple, for all other Accept header values the HTML5 response will be returned. The default action will be to return the standard-sized HTML5 page (the return of the smaller sized mobile version is likely to depend on the result of some User-Agent string inspection on the server side).
Adding REST API support to an existing framework like Alpha will be challenging but rewarding. The ability to think of data in Alpha-based systems as business objects, which can be viewed in a number of different formats (HTML, RSS, Atom, PDF, Excel, and soon XML and JSON) is a core concept of the Alpha Framework. The business object, reflecting the real-world concern we wish to capture, should be abstracted from the concerns of how it will be represented to the user in terms of formats. REST API support goes a step further however, as it requires modification of the controller logic in Alpha to handle the different HTTP verbs, so it is a much bigger addition to the framework than, say, adding another object renderer.
You will notice in all of this that I have not mentioned SOAP. I have done a lot of work with SOAP over the years and there are some things that I like about it in comparison to REST, like the design-by-contract that a WSDL gives you. However, Alpha is squarely focused on the web application space, not the enterprise application space, and right now on the web REST is the dominant approach for public APIs, and with good reason: it makes better use of the HTTP protocol than SOAP does and HTTP is the backbone of the web.
Updated 2022 : note that the above post was originally published in 2011, but is left here for archival purposes. I have fixed some external links above.