2

For some time I used PUT or PATCH in order to update a REST API resource. After using a lot of PUT/PATCH calls I noticed that "update" could be also done with POST.

Here is an example which is oversimplified that will hopefully explain the situation. There is an endpoint /api/cars/dealers/1 with a resource

{
  "id": 1,
  "dealer_name": "Audi Atlanta",
  "year_opened": 2010,
  "contact_persons": [
    {
      "contact_person_type": "main_contact",
      "contact_person_name": "Mike Smith"
    },
    {
      "contact_person_type": "billing_contact",
      "contact_person_name": "Luke Johnson"
    }
  ]
}

Would it be against REST API guidelines if I update this resource with POST such as

{
  "contact_to_change": "main_contact",
  "contact_name": "John Smith"
}

instead of PATCH with

{
  "id": 1,
  "contact_persons": [
    {
      "contact_person_type": "main_contact",
      "contact_person_name": "Mike Smith"
    }
  ]
}

or instead of full resource update with PUT

Please notice how the structure of payload is completely different then the structure of the resource itself. There are cases when this is much more easier then to go with a raw resource update following the same body structure.

Could this way bring some issue that I don't see at the moment?

  • In addition to the other answers i would point out that you can really do the opposite of what you are suggesting too (i.e. use a PUT/PATCH request to the base recourse to create a entry), it all depends on the back end of the web server. But good practice suggests that you don't do this, following good practice can save you a lot of trouble later on. see restapitutorial.com/lessons/httpmethods.html to get a better understanding of how a web server should react to cretin types. – zaza Apr 26 '17 at 0:58
3

You can use POST to update a resource but not using the same URL as the resource you're updating. So, if the URL to use with PUT/PATCH is /api/cars/dealers/1, you'd have /api/cars/dealerupdates to send your POST requests with body as in your PATCH request.

This way it's clear that you're not creating new entity under /api/cars/dealers/ or /api/cars/dealers/1. What created is new update entity which will be applied at some point to the entity inside the request. Another way to see it is: sending GET request to /api/cars/dealerupdates can give a list of updates that have been processed.

  • You can use POST to update a resource but not using the same URL as the resource you're updating this is not fully correct. It is not common, I admit, but one could use the format of the payload received to determine what to kind of operation to perform on that endpoint. Think of a Web form (that only supports POST) that has a choice flag for either updating or deleting an entry and the request goes to the same URI. According to the RFC the request will be processed by the server's own semantic, so it is possible. – Roman Vottner Oct 31 at 17:02
  • I would add to this that it might be useful to create a new URI for the newly created dealerupdates resource that would be returned on success. You could do things like e.g. have a GET on that URI provide a status of the update. – JimmyJames Nov 1 at 15:36
1

depends a bit on the semantics of your messages

a POST to /api/cars/dealers/1/update would be fine since you are sending a new update request (and the semantics changes slightly since the update request might or might not be processed at a later time)

You could even post different structured updates to /api/cars/dealers/1/update. This would allign more with a CQRS kind of architecture where queries would be separated from commands (updates) and then commands are kind of structured as it's own entities.

but generally speaking a POST should create something, either a new contact person (post to /api/cars/dealers/1/contact) or a new update request.

  • ... generally speaking a POST should create something ... a POST request may be used to create something (so a PUT or PATCH request could), though it is not limited to it. It should be used in all cases where the semantics of the other HTTP operations do not fit perfectly. As the request is processed by the server's own semantics the server is basically free to do whatever it wants with the request. It might start a backing process, or alter existing ones or it might create a new one. For the latter though it has to return a Location header in the response to indicate a resource creation – Roman Vottner Oct 31 at 17:12
1

There's a subtle difference between yes, you can use POST for updates and yes, it's ok using POST for updates.

Technically, you can but it's not ok; unless you deal with some rare constraints or you are implementing an RPC web interface.

Why is not ok? The reason is in the other two answers and comments. It's weird. It's confusing.

Confusing? For whom? On one side, for whoever is familiar with the HTTP verbs and have to work with your API. On the other hand, Http clients are implemented to work in a very specific way. Ok, your idea will work on most of the Http clients out there, but you will be making someone else job harder when all too sudden the client stops working as expected.

Allow me to share a reflection. Often, we have what I call "happy ideas". Happy ideas make a lot of sense to us. We are something obvious, brilliant, they work, they are ok.

The thing is if we reach them upon false premises or rationales, lack of knowledge or absolute ignorance.

If you are familiar with the HTTP semantics and you don't want your API to cause some funny WTF time, then you won't use POST for updates. Because it's weird and it makes hard someone's else job. It bears an unnecessary cognitive burden.

Could this way bring some issues that I don't see at the moment?

Hard to say. It will depend on how the happy idea is complicating things. If you have to make this question to strangers on the internet then it's not a good idea. Learn HTTP first, get familiar with it. Then twist it safely as you deem it necessary.

0

In my sense of understanding the term REST API already leans heavily towards an actually RPC-esque thinking of the whole matter as an API is something that should be used by programmers or developers, something that gets invoked and triggers some business processes. It may ship with some fancy documentation that more or less marks the guidelines for developers on how to interact with that API and that becomes the truth for the API itself preventing the API from future evolution as it has to stick to the documentation. Of course, the documentation can be updated. Though this will later on lead to API versioning and questions regarding how to serve clients that support version N but not M in future. We know those problems already for decades from RPC (SOAP, Corba, RMI, ...). Though this is not what REST is and should be.

Fielding defined REST as architectural style. According to Robert C. "Uncle Bob" Martin an architecture is about intent and the intent behind REST is the decoupling of clients from servers to allow the latter ones to evolve freely in future without having to fear breaking clients. In order to achieve decoupling clients and servers have to adhere to a certain set of constraints, which are not an option but mandatory to adhere to. It is too easy to introduce a coupling, that's why we don't see plenty of accurate implementations yet out in the world, except for the WWW.

REST basically reuses the concepts that made the Web so successful and applied it onto the application domain where things were historically RPC driven and therefore tightly coupled. Due to the coupling a lot of services suddenly stopped working when the service changed in one way or the other, this is usually true for all these so called "REST APIs".

On taking a closer look at the WWW, one might recognize that clients use links to retrieve new state and use HTML forms for sending data to the server. The form teaches a client how a request sent to the server has to look like. It contains the endpoint to send the data to and may also contain the method to use as well as the media-type to format the data into before sending it to the server. While certain hypertext-enabled media-types exist (i.e. HAL JSON, ...) the support for hypertext enabled forms is still a bit in its infancy. There are some drafts available but none yet really widely supported yet.

After using a lot of PUT/PATCH calls I noticed that "update" could be also done with POST

...

Would it be against REST API guidelines if I update this resource with POST ...

It depends, but what are REST API guidelines anyways? They aren't standardized so one might state this, one other state just the opposite. Which one is now true? Most of these guidelenes state that verbs should not be present within URIs as they have an RPC smell to it. Though in reality in a REST environment the form of the URI is not of importance at all. It is just use to send requests to. A client shouldn't analyze the URI as the server is basically free to change the URI at any time it wants to. There are already way to many API-specific clients out there that consider certain endpoints to return certain types instead of relying on content-type negotiation to retrieve a representation of the data it can actually process and work upon. The URI itself is not the important part, accompanying data such as link relations or some human readable text as defined by a standardized media-type are more important. We humans also prefer reading some human readable text summarizing the content of a link than the actual link itself that my contain cookie information and encrypted parameters and what not. I therefore would be careful which guidelines to follow.

If using POST to update data would be against REST principles in general, than the big cousin, the WWW, which the whole idea behind REST stems from, would also not adhere to principles REST implies. HTML, the de-facto standard document format exchanged most of the time for Web pages, only supports POST and GET. HTTP would be fine to accept DELETE, PATCH, PUT or any of the other standardized HTTP operations, though HTML decided to only support those two mentioned and it was able to solve all of the tasks at hand.

RFC 7231 defines POST in a way that it can be used as all-purpose-toolkit which you have to use especially when the semantics of the other operations don't fit the task at hand. This does, however, not mean that you should use only POST from now on. I.e. if you deal with monetary transactions you do want to use PUT, due to the idempotent promise it gives to clients, as pointed out by Jim Webber in a great talk back from 2011. Even though everything seems to be super-fast and almost local nowadays, we are still dealing with a remote infrastructure where network hick-ups or other temporary errors may occur. In case of network failures it is good to know for a client whether a request can blindly get resent or will lead to a further processing. There even evolved certain creation pattern around such promises.

The main premise in a REST architecture should always be that a server should teach a client on what it can do next. A set of options is given to the client in the form of links it may invoke if interested in the content of that link. Based on link-relation and other accompanying data a client should determine whether it is interested in retrieving that information or not. A server can teach a client that it requires further input by sending a form representation to the client and based on the affordance of the contained elements a client knows, without the need of some external documentation, what the server expects and can act accordingly. This is basically what HATEOAS is all about. Giving a client options and teaching it what the server expects. According to Jim Webber you basically implement a domain application protocol based on a finite state machine that is progressed through by clients through links and form-input requests.

As can be seen in HTML, the media type may specify or restrict the usable HTTP operations further. For all-purpose, general media-types this is probably not the norm, but certain media types, such as HTML, do. And you should adhere to these if you don't want to run into interoperability issues down the road.

Could this way bring some issue that I don't see at the moment?

As mentioned above, certain HTTP operations offer different semantics and promises to clients. I.e. when a network issue occurs on a PUT request a client knows that it simply can resend the request without any deeper thoughts as its expectations are that the request will be treated in an idempotent manner leading to the same outcome regardless if the request was received once or multiple times. On using POST, however, the client can't be sure if the request did not reach the server or the response of that request just got lost mid way. The client has no guarantees in such case what resending the request may cause. In Jim Webber's video I've linked he clearly explains why you want to use PUT for such cases. Note that you technically could handle POST to always behave idempotent on the server-side and PUT to not behave idempotent at all, this doesn't matter to a client as this is surely a server issue. This is the same as if you'd expose an order 10000 supplies of item X via a GET method invocation and now Google comes by and invokes that URI. A client can't be made accountable for such sloppy implementations.

RFC 7231 explicitly states in regards to safe, i.e.:

This definition of safe methods does not prevent an implementation from including behavior that is potentially harmful, that is not entirely read-only, or that causes side effects while invoking a safe method. What is important, however, is that the client did not request that additional behavior and cannot be held accountable for it.

So, long story short, can you use POST as replacement for PUT? Yes, you can. But you shouldn't use it blindly. Especially if data needs to be idempotent you should use PUT instead of POST, even though you could technically treat POST the same way as PUT, the promise the spec gives to clients is clear, and if you violate these, clients must not made accountable for your mistakes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.