Rules for RESTful Web Services
I contend that the best RESTful web services are those that don’t distinguish between web browsers and other user agents. They are characterised by their ability to provide representations of resources that can be utilised by both humans and machines. Furthermore, they voluntarily adhere to additional constraints that simplify the requirements of their RESTful web clients. In this article, I intend to set out 3 rules to help readers implement better RESTful web services.
Rule 1: Limit HTTP Method Usage to GET and POST
Limiting RESTful web services to the GET and POST HTTP methods simplifies RESTful web clients, as they only need to understand the semantics of 2 HTTP methods. The similarities between GET/POST, read/write, query/command and safe/potentially-unsafe are almost universally understood. In addition, HTML forms only support the GET and POST HTTP methods. Whilst it’s possible to tunnel the preferred HTTP method through a header or parameter, it’s not required to satisfy the constraints of REST.
It can be argued that limiting RESTful web services to the GET and POST HTTP methods limits their expressiveness. However, I would argue that expressiveness can be restored and even enhanced by implementing Rule 2…
Rule 2: Model Actions as Resources
This one is controversial. The common, but not necessarily accepted wisdom, is that actions, or verbs, specifically, shouldn’t be modelled as resources, because they would break the Uniform Interface constraint of REST. What’s often lost in this discussion, is that websites have provided resources such as “CreateThis.html” and “ApproveThat.html” for years. When a RESTful Web Client GET’s the “CreateThis.html” resource, it receives a form it can submit (i.e. POST) to the same URL to perform the action. The name of the resource and it’s URL are irrelevant.
Separating forms into their own resources yields additional benefits for the RESTful Web Service. In addition to those resources adhering to the Single Responsibility Principle (i.e. they only have one reason to change), the RESTful Web Service can optimise caching, as forms are unlikely to change that often. Whilst this indirection means that RESTful web clients will need to make an additional request to get a form, it doesn’t mean they have to present the form in a new context. Instead, RESTful web clients can opt to compose form resources with other resources (e.g. by Ajax) to provide a rich user interface.
Rule 3: Prefer 201 Created over Post/Redirect/Get
Web browsers are not concerned with the creation of new resources. They allow for it with their support of the POST HTTP method, but specify no special behaviour for their responses. In order to prevent a duplicate form submission when a user refreshes a page, websites must implement the Post/Redirect/Get pattern. The problem with this pattern is that the redirect does not semantically convey whether or not a new resource was created. This is problematic for machines, because unlike humans, they cannot intuitively validate the result (well, who knows). Also, some user agents may simply not want to redirect to the newly created resource.
Unlike in Rule 1 where accommodations were made (and justified!) to support web browsers, we can make no such accommodations here. Instead, the web browser must either be detected (e.g. by the Accept header specifying text/html) so that the Post/Redirect/Get pattern can be implemented, or we must perform the redirection in the web browser some other way. Web browsers have long supported a non-standard header called Refresh. This header allows websites to specify a timeout and crucially, a location for the web browser to request. Whilst not ideal, by implementing this header, RESTful web services can serve both web browsers and other user agents without compromise.
The Third Rail of Software Development
In this article I set out 3 rules to help readers implement better RESTful web services. Whilst these rules do not represent a complete list, I hope they inspire further inquiry. Advanced readers will have already drawn parallels between some of these rules and architectural styles such as CQRS (inc. Task-Based UIs). At the very least, I hope that they move readers with data-centric mindsets to more resource-orientated mindsets.
Publicly discussing REST is the third rail of software development — touch it and you die. It is simply too broad a topic to cover with any degree of safety. The very premise of this article — that the best RESTful web services are those that don’t distinguish between web browsers and other user agents — assumes far too much. Ultimately, readers will have to make up their own minds as to whether the rules set out are applicable to their particular problem domain.