Roblog

home about me text processing with ruby

An introduction to HTTP verbs

20 September 2013

Verbs. Doing words. They’re the building blocks of much of our human communication, and the web is no different: HTTP, the protocol on which the web runs, uses them as one of its primary concepts.

In HTTP’s terms, verbs are called “request methods”, and they determine how the server should respond to a particular request. They mean that, if a URL defines a resource (a blog post, for example, or an image), different actions can be performed on that resource without needing to create different URLs or pass different types of request data.

Web developers are generally familiar with GET and POST requests; they’re the ones that you encounter if you’ve ever made a site with basic forms on it.

I certainly discovered these two methods quickly, but took quite a while to realist that there were more — let alone discover uses for them. But there are indeed more, and they can be pretty useful.

The methods

The valid HTTP methods are GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, and PATCH.

This panoply of actions is great, but not all of them are particularly useful for web developers; so, I’m going to focus on the main and most useful five.

GET

GET is, as discussed, by far the most common type of request. Along with HEAD, it’s the only one that webservers are required to implement.

It also has some special qualities. GET requests should fetch information, and that’s it; they should have no side-effects, make no modifications to the system, create nothing, and destroy nothing. They should, in other words, be “safe” and “idempotent” (see below for more disussion about idempotency).

If we imagine a messageboard, we’d use GET requests to browse topics and messages within it. If the user wanted to view an individual message with the ID 123, they’d like make the following request:

GET /message/123

The expectation of a user would be that the body of the response would contain information about that message; it might be an HTML webpage, or it might be some JSON containing data for that message.

A HEAD request is functionally identical to a GET, but instead of returning the response body — so, typically, the HTML content of a page, or the JSON result returned by an API, and so on — only the headers are returned.

This allows you to check the headers before deciding whether or not to fetch the whole body. So, you might check what the Last-Modified value was, to see if your local copy was out of date; if it was, you could then make a GET request.

POST

Strictly speaking, a POST request is a statement by the client that a new “subordinate resource” should be created beneath the given URI.

In practice, that means that POST requests should be used for things like adding a new post to a messageboard thread, adding a new post to a blog; or sending a message via a contact form.

The “subordinate resource” wording makes things seem complex, but it actually makes sense. In our messageboard example, if we wanted to create a new message we’d likely make the request:

POST /message

Then what you’re saying to the server is “create a new ‘message’, using the information I’m providing in this request”. That new message is our “subordinate resource”.

PUT

A PUT request instructs the server to replace a resource. So if you were to send the request:

PUT /message/123

You’d be saying something like: “replace the message with the ID 123 with the contents of this request”.

This might be used for editing an existing post on a blog, updating a record in a CRM — anything where the operation is replacing an existing resource.

DELETE

Perhaps the simplest of all to understand, a DELETE request instructs the server to delete the resource identified by the given URL.

So, to continue our messages example, we might request:

DELETE /message/123

in order to delete the message with the ID 123.

The right verb for the right job

Choosing a verb can be difficult. There are three things to consider: the semantic qualities of the API you’re creating; the practicalities of clients; and the qualities of safeness and idempotency.

The first concern is fairly straightforward: it’s basically the answer to the question “which verb reveals my intentions the most clearly?”. So if the request will delete a resource, it makes most sense for that request to be a DELETE; if the request will modify an existing resource, you might choose PUT; and so on.

The second is more tricky. Browsers, even modern ones, typically allow forms to make only GET and POST requests. Other methods can be used via JavaScript, but if you’d like your actions to be accessible from a regular form, you need to limit yourself to just GET and POST.

Anne van Kesteren has a useful article, albeit from 2007, that outlines the browser support for request methods in AJAX calls.

For the third concern, we’ll need to dig a little deeper.

Safe requests

A request is considered to be “safe” if it doesn’t modify resources. GET and HEAD requests should always be safe; they’re meant to return resources, not alter them.

This has implications for caching; since safe methods don’t alter resources, they can generally be safely cached without fear of altering behaviour.

Idempotency and side-effects

Idempotency is a highfalutin’ maths word, but behind it is a relatively simple concept. It’s the idea that, no matter how many times you perform an action, the state of the system you’re dealing with will remain the same.

Consider a PUT request:

PUT /messages/123

After we run this request, the message with the ID 123 will have been updated with the body of our request. If we run it again, there will be no difference; the message with the ID 123 will be the same. We could run this request over and over and over again, and nothing would be different; because of this, we can say that this request is idempotent.

Contrast this with a POST request:

POST /messages

This request will create a new message. If we run the request again, another message will be created; if we run it a third time, we’ll have created three new messages, and so on. For this reason, this request is not idempotent: the state of the system (i.e. how many posts there are) depends on how many times we’ve made this request.

Conclusions

A well-designed API is one that has good semantic value, and that reveals its intentions to its users. I know that if I make a DELETE request to a particular resource I’m going to end up deleting that resource; if I make a GET request, I can hopefully be confident that I’m going to merely fetch the resource and not cause any side-effects.

Choosing your verbs carefully will mean you have to write less documentation, have to manage fewer URLs in your backend code, and have to write less parameter-checking boilerplate.