0

I am creating a web client which has the purpose of modifying a set of database tables by adding records to them and removing records from them. It must do so atomically, so both deletion and insertion must be done with a single HTTP request. Clearly, this is a write operation of some sort, but I struggle to identify which method is appropriate.

POST seemed right at first, except that RFC 2616 specifies that a POST request must describe "a new subordinate" of the named resource. That isn't quite what I'm doing here.

PUT can be used to make changes to existing things, so that seemed about right, except that RFC 2616 also specifies that "the URI in a PUT request identifies the entity enclosed with the request [...] and the server MUST NOT attempt to apply the request to some other resource," which rules that method out because my URI does not directly specify the database tables.

PATCH seemed closer - now I am not cheating by only partly overwriting a resource - but RFC 5789 makes it clear that this method, like PUT, must actually modify the resource specified by the URI, not some subordinate resource.

So what method should I be using?

Or, more broadly for the benefit of other users:

For a request to X, you use

  • POST to create a new subordinate of X,
  • PUT to create a new X,
  • PATCH to modify X.

But what method should you use if you want to modify a subordinate of X?

Community
  • 1
  • 1
Colin P. Hill
  • 422
  • 4
  • 18
  • First things first. If you want to use proper HTTP methods (as is a Restfull application) you should not have a single request touching more than one resource (if you see your tables as resources). If all this updates represent 1 single change of 1 single resource, then you should use PUT – Plínio Pantaleão Oct 08 '14 at 21:25
  • I was considering the subordinate resource to be the aggregate entity described by the multiple tables - it is not a single thing I can have a pointer to, but it is a conceptual abstraction laid on top of the database structure (manipulated through procs written to support this abstraction). Could you justify why PUT is correct even though the URI does not name the resource(s) being changed? – Colin P. Hill Oct 08 '14 at 21:33
  • To clarify a point, the actual resource being modified - the particular database abstraction - is specified by a parameter in the request body. The URI, therefore, is definitely not a unique identifier for it, and instead identifies the request handler which does a little preprocessing. – Colin P. Hill Oct 08 '14 at 21:36
  • @PlínioPantaleão there is nothing wrong with a single REST request affecting many resources, as long as they do so through a single logical resource. Remember, the representations that the clients deal with have nothing to do with how the server actually stores data. – thecoshman Aug 19 '15 at 08:11
  • @thecoshman That's the reason I put in parentesis my assumption the each table represents a resource. I know that there is no need for that to be true, but it is what I have understand of the problem – Plínio Pantaleão Aug 20 '15 at 14:48

4 Answers4

0

To start.. not everything has to be REST. If REST is your hammer, everything may look like a nail.

If you really want to conform to REST ideals, PATCH is kind of out of the question. You're only really supposed to transfer state.

So the common 'solution' to this problem is to work outside the resources that you already have, but invent a new resource that represents the 'transaction' you wish to perform. This transaction can contain information about the operations you're doing in sequence, potentially atomically.

This allows you to PUT (or maybe POST) the transaction, and if needed, also GET the current state of the transaction to find out if it was successful.

In most designs this is not really appropriate though, and you should just fall back on POST and define a simple rpc-style action you perform on the parent.

Evert
  • 93,428
  • 18
  • 118
  • 189
  • The point on not being bound to REST is well-received - I really only want to investigate the feasibility of conforming, but in the end I'll use a freaking GET if that's what seems best. But the rest of your post is not clear to me. In particular: 1) I already have a resource dedicated to the transaction - an ASP page that communicates with my database - and I am already *able* to PUT or POST to it, but that doesn't help me ascertain the "correct" verb to use. 2) I have no idea what you mean by an "rpc-style action", nor how this amounts to an alternative to a resource for the transaction. – Colin P. Hill Oct 09 '14 at 12:30
  • I think you need to be a lot more specific to get a specific answer, but my general point was .. you probably just want to use `POST` and with rpc-style action I meant: the body will probably contain information about an operation/function call and is not a simple transfer of resource state. – Evert Oct 09 '14 at 15:04
  • `PATCH` is most certainly *the* way to solve this. You want to make a partial modification to the 'data base' resource. Your body will be something like `{ "delete":[ ], "create": [ ] }`. You are sending a `PATCH` to the state, a delta if you will. – thecoshman Aug 19 '15 at 07:51
  • @thecoshman From a pure 'best tool for the job' point of view, you are probably right. My point was that that if you stick academically to REST, there should not be a `PATCH` operation at all. – Evert Aug 19 '15 at 16:54
  • @Evert I'm really curious about your justification for that. – thecoshman Aug 19 '15 at 16:57
  • I have to prefix this with that this is my interpretation of the dissertation. A lot of the robustness of the REST architecture stems from its statelessness. REST is stateless because you transfer full resources. A `PATCH` method is not idempotent, so its outcome might rely on the current server state. You can't assume you can always repeat a failed `PATCH` and get the same outcome. – Evert Aug 19 '15 at 17:24
  • In particular read the "Stateless" chapter in the dissertation here: https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm The following sentence is especially important: "such that each request from client to server must contain all of the information necessary to understand the request,". I would argue that you cannot fully understand the `PATCH` request unless you also know the server state. – Evert Aug 19 '15 at 17:27
  • @Evert I think you have misunderstood some details here. The statelessness of REST is that server does not track what the client is doing. The client can't ask to "get the current thing" as the server doesn't know what the current thing is, the client has to track that and ask for that URI itself. So, when the client `PATCH`s a resource, in the clients model, that resource exists, and the client wishes to make ~these~ changes. The `PATCH` request contains all the information required for the server to make the changes requested. – thecoshman Aug 20 '15 at 14:03
  • You could start to worry about version, but then you would do with `PUT`. If you wanted to ensure that a client was updating based on the latest view, then when they `PUT` you would require they also say what version they got earlier. Yes, there version is a state, but the key thing is that the server stores *its own state* and not *the clients* state. REST is not stateless, it is the transfers that are stateless. (ps, find me in [the lounge](https://chat.stackoverflow.com/rooms/10/loungec) and make a new chat room for us to continue this if you like) – thecoshman Aug 20 '15 at 14:05
0

RFC 2616 is obsolete. Please read RFC 723* instead, in particular https://datatracker.ietf.org/doc/html/rfc7231#section-4.3.3.

Armen Michaeli
  • 8,625
  • 8
  • 58
  • 95
Julian Reschke
  • 40,156
  • 8
  • 95
  • 98
  • Huh, I didn't know about that. Shall I take this to imply that, under the new, vaguer definition of POST, you advocate using that method for this sort of thing? – Colin P. Hill Oct 09 '14 at 12:45
0

First, allow me to correct your understanding of these methods.

POST is all about creating a brand new resource. You send some data to the server, and expect a response back saying where this new resource is created. The expectation would be that if you POST to /things/ the new resource will be stored at /things/theNewThing/. With POST you leave it to the server to decide the name of the resource that was created. Sending multiple identical POST requests results in multiple resources, each their own 'thing' with their own URI (unless the server has some additional logic to detect the duplicates).

PUT is mostly about creating a resource. The first major difference between PUT and POST is that PUT leaves the client in control of the URI. Generally, you don't really want this, but that's getting of the point. The other thing that PUT does, is not modify, if you read the specification carefully, it states that you replace what ever resource is at a URI with a brand new version. This has the appearance of making a modification, but is actually just a brand new resource at the same URI.

PATCH is for, as the name suggest, PATCHing a resource. You send a data to the server describing how to modify a particular resource. Consider a huge resource, PATCH allows you to send just the tiny bit of data that you wish to change, whilst PUT would require you send the entire new version.

Next, consider the resources. You have a set of tables each with many rows, that equates to a set of collections with many resources. Now, your problem is that you want to be able to atomically add resources and remove them at the same time. So you can't just POST then DELETE, as that's clearly not atomic. PATCHing the table how ever can be...

{ "add": [
  { /* a resource */ },
  { /* a resource */ } ],
  "remove" : [ "id one", "id two" ] }

In that one body, we have sent the data to the server to both create two resources and delete two resources in the server. Now, there is a draw back to this, and that is that it's hard to let clients know what is going on. There's no 'proper' way of the client of the two new resources, 204 created is sort of there, but is meant have a header for the URI of the one new resource... but we added two. Sadly, this a problem you are going to face no matter what, HTTP simple isn't designed to handle multiple resources at once.


Transaction Resources

So this is a common solution people propose, and I think it stinks. The basic idea is that you first POST/PUT a blob of data on the server the encodes the transaction you wish to make. You then use another method to 'activate' this transaction.

Well hang on... that's two requests... it sends the same data that you would via PATCH and then you have fudge HTTP even more in order to somehow 'activate' this transaction. And what's more, we have this 'transaction' resource now floating around! What do we even do with that?

thecoshman
  • 8,394
  • 8
  • 55
  • 77
0

I know this question has been asked already some time ago, but I thought I should provide some commentary to this myself. This is actually not a real "answer" but a response to thecoshman's answer. Unfortunately, I am unable to comment on his answer which would be the right thing to do, but I don't have enough "reputation" which is a strange (and unnecessary) concept, IMHO.

So, now on to my comment for @thecoshman:

You seem to question the concept of "transactional resources" but in your answer it looks to me that you might have misunderstood the concept of them. In your answer, you describe that you first do a POST with the resource and the associated transaction and then POST another resource to "activate" this transaction. But I believe the concept of transactional resources are somehow different.

Let me give you a simple example:

In a system you have a "customer" resource and his address with customer as the primary (or named) resource and the address being the subordinate address. For this example, let us assume we have a customer with a customerId of 1234. The URI to reach this customer would be /api/customer/1234. So, how would you now just update the customer's address without having to update the entire customer resource? You could define a "transaction resource" called "updateCustomerAddress". With that you would then POST the updated customer address data (JSON or even XML) to the following URI: POST /api/customer/1234/updateCustomerAddress. The service would then create this new transactional resource to be applied to the customer with customerId=1234. Once the transaction resource has been created, the call would return with 201, although the actual change may not have been applied to the customer resource. So a subsequent GET /api/customer/1234 may return the old address, or already the new and updated address. This supports well an asynchronous model for updating subordinate resources, or even named resources.

And what would we do with the created transactional resource? It would be completely opaque to the client and discarded as soon as the transaction has been completed. So the call may actually not return a URI of the transactional resource since it may have disappeared already by the time a client would try to access it.

As you can see, transactional resources should not require two HTTP calls to a service and can be done in just one.

uromahn
  • 39
  • 2