REST: 'There aren't enough verbs'
April 19, 2009
I think one of the more frequent issues that people have when starting to work with a RESTful architecture is that "there aren't enough verbs".
Let's discuss what I mean by 'activity resources'. Generally when people start designing the resource space for their RESTful API they might write a description of what functionality the API seeks to expose, and then go through the text underlining nouns. If this is reminding you of an analysis technique for a certain other paradigm then stick with me, I'll be coming back to that in the next section. This set of nouns would generally be a good starting point for identifying resources. I'll call these types of resources Entity Resources. Let's say we're working on a hotel reservation system. After this initial stage of analysis we might come up with a set of entity resources such as Guest, Room, Hotel, Bill, etc. We'd probably also have Reservation in there too, but I wouldn't classify that one as an entity. So far so good. Now, let's say we're working on the checkout part of the system, in particular on credit card processing. We need a way to represent the act of a Guest paying their Bill with a credit card, having that credit card transaction approved or declined, etc. A lot of developers (particularly those coming from an RPC mindset) will want to do something like add a PAY verb to the Bill resource. This makes sense. Paying is an action that is applied to the Bill. It makes sense, but as we've discussed above REST frowns upon extending our small set of verbs. So instead we can create an Activity Resource called Payment. This resource can contain a reference (in the form of a uri) to the Bill it is a Payment for, along with details like credit card number, etc. In addition we can add a Payments resource which belongs to each Bill. When a customer wants to pay a bill they can send a POST to the Payments resource, supplying a representation of the payment they want to make. That POST will create a Payment resource representing the transaction, and supply the user with a uri for that resource in the form of a redirect. The customer can GET on that resource to check on the state of the payment transaction (Processing,Successful,Denied), etc. Maybe if the payment was denied they could PUT to the resource with a corrected credit card number. The key pattern here was to take an action (paying a bill), and to model that as a transitory Activity resource. Adding that extra level allows us to model the behavior in a RESTful way. I've frequently seen transactions modeled RESTfully in this way.
Why having few verbs is good
When we look at the big picture we see that this paucity of verbs is in fact one of the strengths of REST. A small, standard set of verbs allows all parties to agree (in the most part) on what the semantics of those verbs are. This in turn allows the creation of a lot of loosely coupled infrastructure which any REST system can take advantage of. An obvious example is the sophisticated caching system within the world wide web. All parties can agree on what a GET means, specifically that it's an idempotent operation. That allows intermediaries to know when a response is cachable. If each application was creating its own set of verbs we'd no longer be able to leverage all this 'free' infrastructure which has built up. If a cache somewhere between your user's browser and your data center doesn't understand what the semantics of some custom verb are then it can't safely cache your responses. Same goes for your user's browser. This is one of the reasons why RESTful folks don't like web services with RPC-style architectures. By tunnelling everything through POST and a single URI these services lose the ability to confer semantics to intermediaries. These kinds of services are on the web, but not of the web.What to do when you 'need' more verbs
So, we are agreed that a small, standard set of verbs is a good thing. What then is an API designer to do when modeling a complex operation which doesn't map nicely onto that small set? In my experience there are generally two solutions. We can use an overloaded POST, or we can add some additional 'activity resources' to the resource space of the API. I tend to prefer the latter, but I think it's important to not be dogmatic about this. There are certainly situations where an overloaded POST is the way to go.Let's discuss what I mean by 'activity resources'. Generally when people start designing the resource space for their RESTful API they might write a description of what functionality the API seeks to expose, and then go through the text underlining nouns. If this is reminding you of an analysis technique for a certain other paradigm then stick with me, I'll be coming back to that in the next section. This set of nouns would generally be a good starting point for identifying resources. I'll call these types of resources Entity Resources. Let's say we're working on a hotel reservation system. After this initial stage of analysis we might come up with a set of entity resources such as Guest, Room, Hotel, Bill, etc. We'd probably also have Reservation in there too, but I wouldn't classify that one as an entity. So far so good. Now, let's say we're working on the checkout part of the system, in particular on credit card processing. We need a way to represent the act of a Guest paying their Bill with a credit card, having that credit card transaction approved or declined, etc. A lot of developers (particularly those coming from an RPC mindset) will want to do something like add a PAY verb to the Bill resource. This makes sense. Paying is an action that is applied to the Bill. It makes sense, but as we've discussed above REST frowns upon extending our small set of verbs. So instead we can create an Activity Resource called Payment. This resource can contain a reference (in the form of a uri) to the Bill it is a Payment for, along with details like credit card number, etc. In addition we can add a Payments resource which belongs to each Bill. When a customer wants to pay a bill they can send a POST to the Payments resource, supplying a representation of the payment they want to make. That POST will create a Payment resource representing the transaction, and supply the user with a uri for that resource in the form of a redirect. The customer can GET on that resource to check on the state of the payment transaction (Processing,Successful,Denied), etc. Maybe if the payment was denied they could PUT to the resource with a corrected credit card number. The key pattern here was to take an action (paying a bill), and to model that as a transitory Activity resource. Adding that extra level allows us to model the behavior in a RESTful way. I've frequently seen transactions modeled RESTfully in this way.