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
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 valid HTTP methods are
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 is, as discussed, by far the most common type of request. Along
HEAD, it’s the only one that webservers are required to
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:
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.
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
This allows you to check the headers before deciding whether or not to
fetch the whole body. So, you might check what the
was, to see if your local copy was out of date; if it was, you could
then make a
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:
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 request instructs the server to replace a resource. So if you
were to send the request:
You’d be saying something like: “replace the message with the ID
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.
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:
in order to delete the message with the ID
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
POST requests. Other methods can be used
a regular form, you need to limit yourself to just
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.
A request is considered to be “safe” if it doesn’t modify resources.
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.
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
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.
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
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.