POST, PATCH, and PUT: What’s the Difference?

And why does it matter?

If you’ve used or built a RESTful API, you’ve very likely dealt with GET and POST requests. You’ve probably also dealt with PUT requests. If you’ve encountered PATCH requests, you probably asked yourself how it differs from POST or PUT. The three types of request all contain request bodies, but the similarities start to get more fuzzy from there. Here are some key differences.

POST

POST requests essentially hand over control to the server, allowing it to decide exactly how resources will be created. That is, the server can decide which fields in the request body to accept, what file type (if any) will be created, and what URI will point to the new resource. As RFC 2616 puts it:

The actual function performed by the POST method is determined by the server and is usually dependent on the Request-URI.

Typically, this this means that POST requests are directed at an API endpoint.

POST requests are necessarily not idempotent. Consider the example below. If we want to create a new Pokemon, we’d send a POST request to an the api/pokedex API endpoint (just note that it’s not a real endpoint). We’d send up some required fields: the Pokemon’s name, type, and array of moves.

POST /api/pokedex HTTP/1.1
Host: pokemon.com
Content-Type: application/json
{
"id": 981
"name": "Eighttales",
"type": "ice",
"moves": [
"quick attack",
"gust"
]
}

You can imagine sending the request above twice. While you may get a successful response the first time, the server may send an error the second time. Perhaps the server doesn’t allow more than one Pokemon to have the same name. If the server does respond successfully, the resource created by the the second request would likely contain a different, unique ID and/or URI.

PUT

Rather than targeting an endpoint, PUT targets either an existing resource that is to be updated or the location where a new resource will be created. In both instances, the request entity must include a full representation of the resource.

PUT is a necessarily idempotent operation. Whether a request targets an existing or a nonexistent resource, the server should respond with the same content after every identical PUT. For example:

PUT /pokedex/130.json HTTP/1.1
Host: pokemon.com
Content-Type: application/json
{
"id": 130
"name": "Jirados",
"type": "water",
"moves": [
"splash,
"gust"
]
}

If a resource with the URI /pokedex/130.json already exists, the content of the resource will be replaced by the body of the request above. If it did not exist, a resource will be created, and it will contain the content of the request body. No matter how many times we send the request, the server should respond with the same body every time, and the resource should not continue to change.

PATCH

PATCH probably continues to be the most misunderstood of the requests. It’s relatively new (it’s RFC was written in 2010), and it’s often and incorrectly handled the same way that POST or PUT is used. Unlike PUT, the URI of a PATCH request cannot point to a resource that doesn’t exist.

The most important thing to keep in mind about PATCH is that the request entity should not contain the partial or full representation of an existing resource. RFC 5789 explains what should be sent instead:

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.

Those set of instructions are called patch documents, and they’re based on the type of resource trying to be PATCHed. For JSON, the entity can contain a JSON Patch document(Content-Type: application/json-patch+json) or a JSON Merge Patch document (Content-Type: application/merge-patch+json).

Although a JSON Patch document is JSON, it’s a specific type of JSON. Specifically, a JSON Patch document must be an array of comma-separated JSON objects, each of which contains a valid operation ("op" ) and path. For example:

[
{ "op": "remove", "path": "/a/b/c" },
{ "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] },
{ "op": "replace", "path": "/a/b/c", "value": 42 },
{ "op": "move", "from": "/a/b/c", "path": "/a/b/d" },
{ "op": "copy", "from": "/a/b/d", "path": "/a/b/e" }
]

The restrictions on the document ensure that the server receives concrete instructions that specify how a resource should be updated.

Why does it matter?

Understanding the different use cases for these methods can help create efficient applications. For example, consider a multi-thousand line JSON resource. If a client uses a PUT request to update a single line in the resource, the entire resource would need to be included in the entity. To avoid updating an old version of a resource, the client would likely first make a GET request to the resource. Suddenly, a one-line change means that the enormous resource must be transferred between the server and client three separate times. Supporting the less-understood PATCH would reduce the size of each request and response.

The pokeapi response to a GET request to a single Pokemon contains nearly 10,000 lines of JSON!

HTTP works as the language of the web because it has been standardized. Clients and servers can communicate because they both use the same, standard language. When servers stray away from the accepted standards, users have to spend additional time reading documentation in order to understand how the server chose to interpret the protocol. Following the accepted standards ensures that everyone continues to communicate with the same language.