An introduction to HTTP verbs
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.
HEAD
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.
Add a comment