DEV Community

Cover image for Why you should use standard HTTP methods when designing REST APIs
Suhas Chatekar
Suhas Chatekar

Posted on • Updated on

Why you should use standard HTTP methods when designing REST APIs

One of the characteristics of a good REST API is that it uses the standard HTTP methods in a way they are supposed to be used. We hear this all the time and this is the most fundamental guideline of REST. As generally understood, we use the following HTTP methods while designing REST APIs

  • GET – For returning resources
  • POST – For creating a new resource
  • PUT – For updating a resource
  • PATCH – For updating a resource
  • DELETE – For deleting a resource

But beyond the basics, why is it like that? Isn't use of two methods, PUT and PATCH for an update operation confusing?

What do the specs say?

Let's first get the obvious out of the way. Let's see what the specs say

GET

The GET method requests transfer of a current selected representation for the target resource.GET is the primary mechanism of information retrieval

What this really means is that you should use GET for an API method that returns the latest version of the resource identified by the API URL.

POST

The POST method requests that the target resource process the representation enclosed in the request according to the resource's own specific semantics.
This is slightly confusing but that is because POST can be used to do more than one thing – one of which is creating a new resource.

This is confusing because if the server can perform more than one operations in response to a request then how do consumers find out what happened exactly? The specification says that the server should make use of one of the 2xx family of status codes to indicate to the client what happened on the server.

PUT

The PUT method requests that the state of the target resource be created or replaced with the state defined by the representation enclosed in the request message payload.

So PUT can be used to update a resource as well as to create a new resource. That may sound strange at first, but let's keep things simple for now and trust we should use PUT for an API method that lets consumers update the resource identified by the API URL.

DELETE

The DELETE method requests that the origin server remove the association between the target resource and its current functionality.

Again, like POST, DELETE can be used for more than one operations that eventually result in something being removed. Let's trust we should use DELETE for an API method that let's consumers delete the resource identified by the API URL.

PATCH

The difference between the PUT and PATCH requests is reflected in the way the server processes the enclosed entity to modify the resource identified by the Request-URI. In a PUT request, the enclosed entity is considered to be a modified version of the resource stored on the origin server, and the client is requesting that the stored version be replaced. With PATCH, however, the enclosed entity contains a set of instructions describing how a resource currently residing on the origin server should be modified to produce a new version.

PATCH, like PUT, should be used for modifying a resource, however, the semantics of modification is performed as slightly different. We will get to this difference in the next section.

So our original understanding of what each of the HTTP verbs means is in line with what the specifications say what they mean. So far so good. Specification tells us in which situations we should we use each verb, but it's still just a specification. Our implementation can still disregard what the specification tells us to do and have the creation of new resources implemented behind a GET operation and deletions implemented a POST operation. However, there are two big benefits to respecting the specification.

Idempotence is not limited to mathematics

In mathematics, an idempotent operation is one which produces the same result every time it's performed on the same input. A counter is a good example of this. The operation to “set the counter to 6” is idempotent but the operation to “increment the counter by 1” is not. You see the difference? In the first case, no matter how many times you set the counter to 6, it's still set to 6 in the end. Whereas, in the second case, if the counter had an initial value of 4 and every time you increment it by 1, the counter gets set to different value.

Applied to REST, an idempotent operation is the one which does not change the target state of the server. On the other hand, a non-idempotent operation would always change the target state of the server. Notice that we are not talking about state change here but rather the target state of the server. HTTP specification states that GET, PUT and DELETE are idempotent operations. POST, and PATCH are non-idempotent operations. “Like earlier, this is just a specification. Why do you need to follow it?” you might ask. Well, there is a reason and a very good one.

An idempotent operation gives the consumer of the API a guarantee that the state of the server will be the same no matter how many times they call the API. This guarantee is very useful. Imagine that server executes the API method that consumer called successfully but there is an error while sending the response back to the consumer. The consumer ends up getting an error even though the operation has completed successfully on the server. What should the consumer do? Now, if the operation server performed was advertised as idempotent, then A consumer can send the request to execute the operation one more time. It can keep doing that as long as it sees a success response without causing the server to perform any unwanted state change. On the other hand, if the operation was not advertised as idempotent then the consumer would know that it need to check with the server before performing the operation again.

Creation of a new resource is one operation which changes the target state of the server every time it is run with the same inputs leading to a different target state after each execution. Same may apply to deletion of a resource depending on the implementation. Imagine what would happen if we put these operations behind a GET or a PUT verb? A consumer may end up executing these operations multiple times inadvertently affecting the target state of the server negatively. Returning value of a resource, on the other hand, has no impact on the target state of the server and hence should be implemented behind an idempotent verb GET.

There still is a difference between a PUT and a PATCH. Both are used to modify an existing resource. If you go back to what specification says about PUT you would notice that its similar to saying “set the counter to 6”. PUT is modifications where the consumer provides the target state for the complete resource and instructs the server to replace whatever value the resource has currently with the new value the consumer is sending. No matter how many times the consumer performs this operation, the end state of the resource is never going to change. PATCH, on the other hand, is similar to “increment the counter by 1”. PUT can be chunky for resources that are large in size and eats away a lot of bandwidth. PATCH was introduced to let consumers issue an instruction to the server that tells it how to change a part of the resource. This instruction if executed multiple times could result in an unwanted end state.

In the end, it's all down to the implementation but if your implementation respects the specification then the life of your API clients would be a lot easier. While we are talking about respecting the specification, there is another interesting characteristic that the specification says all HTTP servers and proxies should build when dealing with HTTP request. Your REST API that respects the specification can make good use of this.

Web is fast because of caching

The web is probably one of the heaviest users of cache. It not only makes loading of websites faster, it also works so reliably that not making use of it when it's at our disposal would be foolish. REST uses HTTP and so it should make use of its caching characteristics where possible. The HTTP cache specification is quite detailed about how it should be implemented by HTTP servers and proxies but I would like to pick two things from the specification that directly apply to REST.

  1. An operation behind a GET endpoint does not change the target state of the server, therefore, the response of a GET endpoint can be cached resulting in further requests to the same endpoint being returned faster from the cache
  2. An endpoint behind PUT, POST, PATCH and DELETE changes the target state of the server, therefore, a successful response out of any of these endpoints can be used to bust the previously cached responses.

I know that I am overly simplifying the caching specification of HTTP but this is one of the most elegant caching specification I have come across. And all it takes to take full advantage of this to respect the HTTP specification.

One last thing about caching that impacts the consumers of an API more than the developers of the API. An API that follows HTTP Cache specification is the most useful to a consumer as long as the consumer uses an HTTP client library that supports caching. I am sure there is at least one such library available for every leading programming platform. So encourage your consumers to use one of those libraries. Having said that, API developers should still make use of caching as HTTP and proxy servers will still cache the responses.

In closing

The Beauty of the HTTP API (and I am intentionally avoiding the word REST here) is that it provides a lot of flexibility to the API developer. Any flexibility is a good thing as long as it's not misused. I have seen many HTTP APIs that either does not make use of recommended HTTP methods or if they do, the developer has little knowledge of why he made those choices. I hope this post throws some light on why we should use recommended HTTP methods.

Top comments (23)

Collapse
 
ericrini profile image
Eric Rini

I usually think of PUT as a replace.

given an entity A
when I PUT entity B into A
then B will replace A
    and A will be gone forever
Enter fullscreen mode Exit fullscreen mode

A practical example is saving a new file B to the location of an existing file A.

Likewise, I think of PATCH as a merge.

given an entity A
when I PATCH entity B into A 
then A and B will merge to become C
    and C will replace A
    and A and B will be gone forever
Enter fullscreen mode Exit fullscreen mode

A practical example is writing a new field value B to a SQL record A. The resulting SQL record C contains fields from both A and B.

Collapse
 
suhas_chatekar profile image
Suhas Chatekar

Completely agree with you. That perfectly describes what PUT and PATCH should do.

I avoided using that terminology as I have seen that developers new REST style find it difficult to understand that. And then there is this.

Maybe, this is a topic for its own blog?

Collapse
 
kayis profile image
K

I think idempotence is more important than the verbs.

Using only POST has benefits too.

  • All data is in the body so it doesn't show up in logs.
  • All data is exchanged in the same way in the body, no query parameters.
  • Regular users can't simply copy your API addresses and use them in a browser, because it will always try to GET an URL
Collapse
 
suhas_chatekar profile image
Suhas Chatekar

Yes, idempotence is important but it goes hand in hand with verbs. Browsers and API clients work on the assumption that a POST verb is never idempotent and will behave accordingly so it is important to keep that relationship intact.

I agree with the points you make about advantages of using a POST verb to hide sensitive data.

Collapse
 
kayis profile image
K

Browsers and API clients work on the assumption that a POST verb is never idempotent and will behave accordingly

Does this mean, they assume other verbs to be always idempotent and also behave accordingly?

Thread Thread
 
suhas_chatekar profile image
Suhas Chatekar

I used POST as an example in my statement. What I wanted to say that they will assume what the standard says and behave accordingly.

Collapse
 
bbenjineer profile image
Benjamin Oke

What about checking for authorization before returning such GET requests? Wouldn't it be another way of protecting sensitive data.

Thread Thread
 
suhas_chatekar profile image
Suhas Chatekar

I may be misunderstanding your point but it goes without saying that you always properly protect your API, no matter HTTP method is being used.

Collapse
 
aleron75 profile image
Alessandro Ronchi

Nice article, I didn't focus on PATCH and idempotency so far.

Reading through the article a question arose: say we have an entity with an 'updated_at' attribute where we store the timestamp of the last update.

Since the 'updated_at' is changed every time we save the entity, saving through a PUT method would break the idempotency, is it correct?

In this case, should we consider to use a PATCH to update that kind of entities?

Thank you!

Collapse
 
suhas_chatekar profile image
Suhas Chatekar

It really depends on how your resources are represented.

One way to keep PUT still idempotent in that case would be to treat updated_at as a server generated value which the client has no control over, which is actually true in most cases. The from a client's perspective, the resource representation they send to the server is same every time and server can respond in an idempotent manner.

Collapse
 
aleron75 profile image
Alessandro Ronchi

Ok, that means that a GET shouldn't return the 'updated_at' attribute?
Sorry if I bother :)

Thread Thread
 
suhas_chatekar profile image
Suhas Chatekar

Why should it not?

Resource for PUT and GET can look different.

Thread Thread
 
aleron75 profile image
Alessandro Ronchi

Why should not

Just asking :)

Thank you for your clarification, it was very useful

Collapse
 
gaumala profile image
Gabriel Aumala

Great article, it is good to know about the specs of the HTTP methods, however you can't rely on every client respecting the specification!

Take a look at OkHttp, a Java HTTP client, very popular with android. OkHttp will potentially repeat your requests on a slow/unreliable connection “aggressively” until it succeeds.. It doesn't matter if it is a request with an idempotent method or not, even POST request are retried until the client gets a valid response. OkHttp mantainers argued that everything should be idempotent by default, and unless the client retries the request agressively under the hood on flaky connections, the only way to know whether the request succeeded or not is to make another request at the application layer, which is not pretty. Initially mantainers suggested users to fix their API backends but later they included a flag to disable this. It's been like that for years now.

Collapse
 
suhas_chatekar profile image
Suhas Chatekar

I have very briefly used OkHttp so thanks for bringing this up.

Without getting into why OkHttp decided to aggressively retry even the POST requests, I find the reasoning presented in the medium article half-baked (for the lack of a right word). When you are in the control of the backend API then you can make decisions that go against the standards like HTTP e.g. making POST requests idempotent. However, a good software developer should consider the following two situations

  1. The API you develop today may only have one application as its client that uses OkHttp to interact with the API. But tomorrow, when you more client applications that do not use OkHttp, how do you deal with that?
  2. Integrating with third-party APIs. In this case, you do not have control over how the third party implements POST operations and aggressive retries by OkHttp can actually harm you.

It is a good news that OkHttp now allows disabling this feature. There are better ways to deal with slow internet connections.

Collapse
 
dopitz profile image
Daniel O.

Is this article about REST or "REST" (HTTP API)?

Collapse
 
suhas_chatekar profile image
Suhas Chatekar

I started with REST but ended up writing about REST (HTTP API) ;-)

Collapse
 
earthtone0ne profile image
Stephanie

Can I ask the difference, for my own understanding? Is there something about this that isn't RESTful?

Collapse
 
earthtone0ne profile image
Stephanie

Can I ask the difference? Is there something about this explanation that isn't RESTful, or is it just that REST covers a broader scope than this article?

Thread Thread
 
suhas_chatekar profile image
Suhas Chatekar

REST definitely covers a broader scope than this article - the most important being Hypermedia. This article touches upon a tiny subset of REST.

Collapse
 
nektro profile image
Meghan (she/her)

@ben there's a couple of encoding errors at the top of this article

Collapse
 
suhas_chatekar profile image
Suhas Chatekar

I have fixed the encoding error now. Thanks for pointing out.

Collapse
 
nektro profile image
Meghan (she/her)

Thanks! I really love this article <3