Max Tiu

Max Tiu

The Ins and Outs of PUT and PATCH

June 12, 2016

The world of HTTP is vast! GET and POST are by far the most popular type of requests, but they'll only get you so far. Until recently, the only instances I'd ever really needed to use methods other than GET and POST were server-side while consuming others' APIs; this never proved to be an issue. Lately, however, I've been making more API requests from my own client-side apps, which has brought along some unique challenges. What if you need to update a resource? Meet PUT and PATCH.

What's the Difference?

In practice, I've found most people use the two interchangably. But there are distinct differences!

PUT is for replacing an entire resource with the new version, while PATCH is for updating parts of a resource. So, if you want to explicitly send all attributes of a resource every time you send an update request, use PUT. If you're only updating the fields that changed, use PATCH. However! PATCH is intended to transport a set of instructions detailing how to update a resource, while PUT provides a resource's attributes and values. So while I PUT request may look like this:

PUT /coffee/123
{ 'cream': null, 'sugar': 1 }

A PATCH request might look like this:

PATCH /coffee/123
 { "op": "replace", "path": "/sugar", "value": 1 }

where we are performing the op of replacing the sugar attribute's value with 1. Clearly, the structures of these requests are quite different, so it's up to you which methods you'll support in building an API. William Durand goes into more detail on PATCH's intricacies in his blog post “Please. Don't Patch Like an Idiot.”

What are my OPTIONS?

OPTIONS is a method that checks the requested server to see what it will allow the client to do. Many browsers will automatically send an OPTIONS request before any PUT or PATCH request to ensure that it's allowed as part of CORS preflight checks. If you find your API is rejecting OPTIONS requests when trying to PUT or PATCH, you'll need to define the route and set the Access-Control-Allow-Methods header to include OPTIONS. If you're using Rails, the route will look something like this:

match '/my_resource/:id', to: 'my_resource#update', via: [:options]

PSA: Microsoft Edge is Busted!

One note about using PUT and PATCH client-side: these methods completely break when used in Microsoft Edge! Don't worry, it's not your fault; the latest build of Edge currently has a bug that deletes the body of any PUT or PATCH request and sets Content-Length to 0. Yes, really. No, I can't believe it either. This was pointed out by @javan, who has a wonderful demo repo explaining the problem here. Thankfully, Microsoft already has a fix for this, but it's not yet available in a public release.

What's a girl to do when you've got to support Edge, but also need to make client-side update requests to your API? I'm currently using POST as a workaround, which is awful and I hate it, but it gets the job done. The fix is relatively easy, too, especially if you're using Rails like I am. In addition to the regular resources line in your routes.rb file, you just need to explicitly route the POST method to your update action:

resources :my_resource, only: [:index, :create, :update]
post '/my_resource/:id', to: 'my_resource#update'

And in your client-side app, simply change the method you're using (PUT/PATCH) to POST. Everything should work as previously expected! No, this fix isn't ideal, as it completely goes against the HTTP Protocol. But with PUT and PATCH completely out of commission for an entire browser's worth of users, using them simply isn't an option currently. I'd love to hear any other workaround suggestions that are more Correct if you've got them!