Correct URI for REST calls to create & delete relationship between two entities - rest

I need to create and delete relationships between two different entities through REST calls.
Let's say user A (the current user) is going to follow or un-follow user B. The existence of a follow relationship is denoted by the presense or absence of the Follow relationship entity (Follow(B, A) means that A follows B).
Should the calls be:
POST /api/follow/{user-b-id} // to follow
and
DELETE /api/follow/{user-b-id} // to un-follow
where the identity of user A is deduced from the token sent along to authenticate the call.
Or should they be based on the action being carried out:
POST /api/follow/{user-b-id} // to follow
and
POST /api/unfollow/{user-b-id} // to un-follow
I have doubts about which methods (POST, PUT, DELETE etc.) to use and whether the URIs should reference the action (verb?) being carried out. Since I am re-designing an API, I want to get as close to "correct" (yes, I do realize that's a little subjective) REST API design as makes sense for my project.

Correct URI for REST calls to create & delete relationship between two entities
REST doesn't care what spelling you use for your URI; /182b2559-5772-40fd-af84-297e3a4b4bcb is a perfectly find URI as far as REST is concerned. The constraints on spelling don't come from REST, but instead whatever the local coding standard is.
A common standard is to consider a collection resource that includes items; such that adding an item resource to a collection is modeled by sending a message to the collection resource, and removing the item resource is modeled by sending a message to the item resource. The Atom Publishing Protocol, for instance, works this way - a POST to a collection resource adds a new entry, a DELETE to the item resource removes the entry.
Following this approach, the usual guideline would be that the collection resource is named for the collection, with the item resources subordinate to it.
// Follow
POST /api/relationships
// Unfollow
DELETE /api/relationships/{id}
id here might be user-b-id or it might be something else; one of the core ideas in REST is that the server is the authority for its URI space; the server may embed information into the URI, at it's own discretion and for its own exclusive use. Consumers are expected to treat the identifiers as opaque units.
I have doubts about which methods (POST, PUT, DELETE etc.) to use and whether the URIs should reference the action (verb?) being carried out.
It's sometimes helpful to keep in mind that the world wide web has been explosively successful even though the primary media type in use (HTML) supports only GET and POST natively.
Technically, you can use POST for everything. The HTTP uniform interface gives you carte blanche.
PUT, DELETE, PATCH can all be considered specializations of POST: unsafe methods with additional semantics. PUT suggests idempotent replace semantics, DELETE suggests remove, PATCH for an all or nothing update.
Referencing the action isn't wrong (REST doesn't care about spelling, remember), but it does suggest that you are thinking about the effects of the messages rather than about the resources that the messages are acting upon.
JSON Patch may be a useful example to keep in mind. The operations (add, remove, replace, and so on) are encoded into the patch document, the URI specifies which resource should be modified with those operations.
Jim Webber expressed the idea this way - HTTP is a document transfer application. Useful work is a side effect of exchanging documents. The URI identify the documents that are used to navigate your integration protocol.
So if you need consistent, human readable spellings for your URI, one way to achieve this is by articulating that protocol and the documents from which it is composed.
Would it be correct to say that PUT is for replacing the entire entity (resource) and PATCH if for modifying a sub-set of the entity's (resource's) properties?
Not quite. PUT means the message-body of the request is a replacement representation of the resource. PATCH means the message-body of the request is a patch document.
There's nothing in the semantics that prevents you from using PUT to change a single element in a large document, or PATCH to completely replace a representation.
But a client might prefer PATCH to PUT because the patch document is much smaller than the replacement representation. Or it might prefer PUT to PATCH because the message transport is unreliable, and the idempotent semantics of PUT make retry easier.

The right decision also depends on the way other resources are mapped in the project. Same style is better, however if there's no preference, the following could have the advantage of being easier to implement and remember
POST /api/follow/{user-b-id} // to follow
and
POST /api/unfollow/{user-b-id} // to un-follow

I would say, use the delete verb if your are passing in the id of the relationship/link/follow from a to b. This way, it is fairly explicit your route is doing. It is accepting an id of some object and deleting it.
However, in your example, you are passing in the id of the other user, then you have to do some logic to find the relationship/link/follow object between the two and delete it. In my mind, this is more of a post than a delete because of the additional work you have to do. Regardless, it seems fairly subjective as to which one is "right",

Related

REST delete multiple items in the batch

I need to delete multiple items by id in the batch however HTTP DELETE does not support a body payload.
Work around options:
1. #DELETE /path/abc?itemId=1&itemId=2&itemId=3 on the server side it will be parsed as List of ids and DELETE operation will be performed on each item.
2. #POST /path/abc including JSON payload containing all ids. { ids: [1, 2, 3] }
How bad this is and which option is preferable? Any alternatives?
Update: Please note that performance is a key here, it is not an option execute delete operation for each individual id.
Along the years, many people fell in doubt about it, as we can see in the related questions here aside. It seems that the accepted answers ranges from "for sure do it" to "its clearly mistreating the protocol". Since many questions was sent years ago, let's dig into the HTTP 1.1 specification from June 2014 (RFC 7231), for better understanding of what's clearly discouraged or not.
The first proposed workaround:
First, about resources and the URI itself on Section 2:
The target of an HTTP request is called a "resource". HTTP does not limit the nature of a resource; it merely defines an interface that might be used to interact with resources. Each resource is identified by a Uniform Resource Identifier (URI).
Based on it, some may argue that since HTTP does not limite the nature of a resource, a URI containing more than one id would be possible. I personally believe it's a matter of interpretation here.
About your first proposed workaround (DELETE '/path/abc?itemId=1&itemId=2&itemId=3') we can conclude that it's something discouraged if you think about a resource as a single document in your entity collection while being good to go if you think about a resource as the entity collection itself.
The second proposed workaround:
About your second proposed workaround (POST '/path/abc' with body: { ids: [1, 2, 3] }), using POST method for deletion could be misleading. The section Section 4.3.3 says about POST:
The POST method requests that the target resource process the representation enclosed in the request according to the resource's own specific semantics. For example, POST is used for the following functions (among others): Providing a block of data, such as the fields entered into an HTML form, to a data-handling process; Posting a message to a bulletin board, newsgroup, mailing list, blog, or similar group of articles; Creating a new resource that has yet to be identified by the origin server; and Appending data to a resource's existing representation(s).
While there's some space for interpretation about "among others" functions for POST, it clearly conflicts with the fact that we have the method DELETE for resources removal, as we can see in Section 4.1:
The DELETE method removes all current representations of the target resource.
So I personally strongly discourage the use of POST to delete resources.
An alternative workaround:
Inspired on your second workaround, we'd suggest one more:
DELETE '/path/abc' with body: { ids: [1, 2, 3] }
It's almost the same as proposed in the workaround two but instead using the correct HTTP method for deletion. Here, we arrive to the confusion about using an entity body in a DELETE request. There are many people out there stating that it isn't valid, but let's stick with the Section 4.3.5 of the specification:
A payload within a DELETE request message has no defined semantics; sending a payload body on a DELETE request might cause some existing implementations to reject the request.
So, we can conclude that the specification doesn't prevent DELETE from having a body payload. Unfortunately some existing implementations could reject the request... But how is this affecting us today?
It's hard to be 100% sure, but a modern request made with fetch just doesn't allow body for GET and HEAD. It's what the Fetch Standard states at Section 5.3 on Item 34:
If either body exists and is non-null or inputBody is non-null, and request’s method is GET or HEAD, then throw a TypeError.
And we can confirm it's implemented in the same way for the fetch pollyfill at line 342.
Final thoughts:
Since the alternative workaround with DELETE and a body payload is let viable by the HTTP specification and is supported by all modern browsers with fetch and since IE10 with the polyfill, I recommend this way to do batch deletes in a valid and full working way.
It's important to understand that the HTTP methods operate in the domain of "transferring documents across a network", and not in your own custom domain.
Your resource model is not your domain model is not your data model.
Alternative spelling: the REST API is a facade to make your domain look like a web site.
Behind the facade, the implementation can do what it likes, subject to the consideration that if the implementation does not comply with the semantics described by the messages, then it (and not the client) are responsible for any damages caused by the discrepancy.
DELETE /path/abc?itemId=1&itemId=2&itemId=3
So that HTTP request says specifically "Apply the delete semantics to the document described by /path/abc?itemId=1&itemId=2&itemId=3". The fact that this document is a composite of three different items in your durable store, that each need to be removed independently, is an implementation details. Part of the point of REST is that clients are insulated from precisely this sort of knowledge.
However, and I feel like this is where many people get lost, the metadata returned by the response to that delete request tells the client nothing about resources with different identifiers.
As far as the client is concerned, /path/abc is a distinct identifier from /path/abc?itemId=1&itemId=2&itemId=3. So if the client did a GET of /path/abc, and received a representation that includes itemIds 1, 2, 3; and then submits the delete you describe, it will still have within its own cache the representation that includes /path/abc after the delete succeeds.
This may, or may not, be what you want. If you are doing REST (via HTTP), it's the sort of thing you ought to be thinking about in your design.
POST /path/abc
some-useful-payload
This method tells the client that we are making some (possibly unsafe) change to /path/abc, and if it succeeds then the previous representation needs to be invalidated. The client should repeat its earlier GET /path/abc request to refresh its prior representation rather than using any earlier invalidated copy.
But as before, it doesn't affect the cached copies of other resources
/path/abc/1
/path/abc/2
/path/abc/3
All of these are still going to be sitting there in the cache, even though they have been "deleted".
To be completely fair, a lot of people don't care, because they aren't thinking about clients caching the data they get from the web server. And you can add metadata to the responses sent by the web server to communicate to the client (and intermediate components) that the representations don't support caching, or that the results can be cached but they must be revalidated with each use.
Again: Your resource model is not your domain model is not your data model. A REST API is a different way of thinking about what's going on, and the REST architectural style is tuned to solve a particular problem, and therefore may not be a good fit for the simpler problem you are trying to solve.
That doesn’t mean that I think everyone should design their own systems according to the REST architectural style. REST is intended for long-lived network-based applications that span multiple organizations. If you don’t see a need for the constraints, then don’t use them. That’s fine with me as long as you don’t call the result a REST API. I have no problem with systems that are true to their own architectural style. -- Fielding, 2008

REST design for update/add/delete item from a list of subresources

I would like to know which is the best practice when you are having a resource which contains a list of subresources. For example, you have the resource Author which has info like name, id, birthday and a List books. This list of books exists only in relation with the Author. So, you have the following scenario:
You want to add a new book to the book list
You want to update the name of a book from the list
You want to delete a book from the list
SOLUTION 1
I searched which is the correct design and I found multiple approaches. I want to know if there is a standard way of designing this. I think the design by the book says to have the following methods:
To add: POST /authors/{authorId}/book/
To update: PUT /authors/{authorId}/book/{bookId}
To delete: DELETE /authors/{authorId}/book/{bookId}
SOLUTION 2
My solution is to have only one PUT method which does all these 3 things because the list of books exists only inside object author and you are actually updating the author. Something like:
PUT /authors/{authorId}/updateBookList (and send the whole updated book list inside the author object)
I find multiple errors in my scenario. For example, sending more data from the client, having some logic on the client, more validation on the API and also relying that the client has the latest version of Book List.
My question is: is it anti-pattern to do this?
SITUATION 1. In my situation, my API is using another API, not a database. The used API has just one method of "updateBookList", so I am guessing it is easier to duplicate this behavior inside my API too. Is it also correct?
SITUATION 2. But, supposing my API would use a database would it be more suitable to use SOLUTION 1?
Also, if you could provide some articles, books where you can find similar information. I know this kind of design is not written in stone but some guidelines would help. (Example: from Book REST API Design Rulebook - Masse - O'Reilly)
Solution 2 sounds very much like old-style RPC where a method is invoked that performs some processing. This is like a REST antipattern as REST's focus is on resources and not on methods. The operations you can perform on a resource are given by the underlying protocol (HTTP in your case) and thus REST should adhere to the semantics of the underlying protocol (one of its few constraints).
In addition, REST doesn't care how you set up your URIs, hence there are no RESTful URLs actually. For an automated system a URI following a certain structure has just the same semantics as a randomly generated string acting as a URI. It's us humans who put sense into the string though an application should use the rel attribute which gives the URI some kind of logical name the application can use. An application who expects a certain logical composition of an URL is already tightly coupled to the API and hence violates the principles REST tries to solve, namely the decoupling of clients from server APIs.
If you want to update (sub)resources via PUT in a RESTful way, you have to follow the semantics of put which basically state that the received payload replaces the payload accessible at the given URI before the update.
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.
...
The target resource in a POST request is intended to handle the
enclosed representation according to the resource's own semantics,
whereas the enclosed representation in a PUT request is defined as
replacing the state of the target resource. Hence, the intent of PUT
is idempotent and visible to intermediaries, even though the exact
effect is only known by the origin server.
In regards to partial updates RFC 7231 states that partial updates are possible by either using PATCH as suggested by #Alexandru or by issuing a PUT request directly at a sub-resource where the payload replaces the content of the sub-resource with the one in the payload. For the resource containing the sub-resouce this has an affect of a partial update.
Partial content updates are possible by
targeting a separately identified resource with state that overlaps a
portion of the larger resource, or by using a different method that
has been specifically defined for partial updates (for example, the
PATCH method defined in [RFC5789]).
In your case you could therefore send the updated book collection directly via a PUT operation to something like an .../author/{authorId}/books resource which replaces the old collection. As this might not scale well for authors that have written many publications PATCH is probably preferable. Note, however, that PATCH requires an atomic and transactional behavior. Either all actions succeed or none. If an error occurs in the middle of the actions you have to role back all already executed steps.
In regards to your request for further literature, SO isn't the right place to ask this as there is an own off-topic close/flag reason exactly for this.
I'd go with the first option and have separate methods instead of cramming all logic inside a generic PUT. Even if you're relying on an API instead of a database, that's just a 3rd party dependency that you should be able to switch at any point, without having to refactor too much of your code.
That being said, if you're going to allow the update of a large number of books at once, then PATCH might be your friend:
Looking at the RFC 6902 (which defines the Patch standard), from the client's perspective the API could be called like
PATCH /authors/{authorId}/book
[
{ "op": "add", "path": "/ids", "value": [ "24", "27", "35" ]},
{ "op": "remove", "path": "/ids", "value": [ "20", "30" ]}
]
Technically, solution 1 hands down.
REST API URLs consist of resources (and identifiers and filter attribute name/values). It should not contain actions (verbs). Using verbs encourages creation of stupid APIs.
E.g. I know a real-life-in-production API that wants you to
do POST on /getrecords to get all records
do POST on /putrecords to add a new record
Reasons to choose solution 2 would not be technical.
For requirement #2 (You want to update the name of a book from the list), it is possible to use JSON PATCH semantics, but use HTTP PATCH (https://tools.ietf.org/html/rfc5789) semantics to design the URL (not JSON PATCH semantics as suggested by Alexandru Marculescu).
I.e.
Do PATCH on /authors/{authorId}/book/{bookId}, where body contains only PK and changed attributes. Instead of:
To update: PUT on /authors/{authorId}/book/{bookId}
JSON PATCH semantics may of course be used to design the body of a PATCH request, but it just complicates things IMO.

Should Odata(V4) actions be invoked only with POST?

Odata V4 Spec says that Actions MAY have observable side effects and should be invoked using HTTP POST. But we do have scenarios where we need to use actions which just modifies some status.
For example :
1.You might want to mark status of a document identified by a id as locked
Endpoint - .../Documents({id})/lock().
Since I am doing a partial update here, In my opinion PATCH is more suitable.2. You might want to offer two ways of deleting a document
a) Just Hide Endpoint - ...../Documents({id}) This is with HTTP DELETE (no disputes)
b) Delete PermanentlyEndpoint - ...../Documents({id})/permanentDelete() This as an ODATA action. In my opinion, HTTP Delete would be more appropriate here instead of HTTP POST.
What is the recommended way to do this from Odata standpoint? Any help here is much appreciated.
Below is the information from SPEC.
SPEC
11.5.4 Actions
Actions are operations exposed by an OData service that MAY have side effects when invoked. Actions MAY return data but MUST NOT be further composed with additional path segments.
11.5.4.1 Invoking an Action
To invoke an action bound to a resource, the client issues a POST request to an action URL. An action URL may be obtained from a previously returned entity representation or constructed by appending the namespace- or alias-qualified action name to a URL that identifies a resource whose type is the same as, or derives from, the type of the binding parameter of the action. The value for the binding parameter is the value of the resource identified by the URL prior to appending the action name, and any non-binding parameter values are passed in the request body according to the particular format.
Thanks in advance
--ksp
From an OData standpoint, you always have to invoke an action with a POST, with any other verb, it won't work.
Both of your examples are things that I personally don't think are well suited to an action as there are already ways to do these things with OData and they use the verbs that you are mentioning.Updating a property is supported with a PATCH and deleting an object is supported with a DELETE. You mention that you have two different types of delete operations, this is more difficult but you could use a custom header to distinguish between them.
An action tends to be something that doesn't fit into the normal CRUD operations so it isn't always clear which HTTP verb should be used for this.
In your examples, it does feel right to want to use DELETE and PATCH. However, the problem comes because we need to have a standard to follow, bear in mind that OData actions are all discoverable through the metadata so could be consumed by a client with no knowledge of what the actions actually do and in this case, we need to have something defined. Since we know that actions affect the server in some way, to me, it seems like POST is the least bad option that is consistent for all actions.
At the end of the day, as the author, your API is yours to command. Just as we shouldn't use properties in C# class design that cause side affects in other properties, that doesn't mean we cant, and it can be pretty common.
From an OData standpoint, PATCH is analogous to using property accessors and actions or POST is for accessing methods.
Making the decision between PATCH or POST to affect change is therefor the same design decision between using property mutators (making them writable) or forcing the caller to set their values through related methods.
You might want to mark status of a document identified by a id as locked
Endpoint - .../Documents({id})/lock().
Since I am doing a partial update here, In my opinion PATCH is more suitable.
If your resource has a property called Locked, and your current lock() Action only sets the Locked property to true, then you could simply use PATCH to update just that Locked field.
Some common reasons to use an Action specifically for a lock process:
You want to execute specific logic when lock() is called and you want to maintain this logic in it's own method, rather than having complex conditional logic inside your patch handler.
You don't want the reverse logic, unlock() to be available to everyone, when a resource is locked, presumably only the user who locked it can release the lock or other conditions need to be satisfied.
as with the first point, this sort of logic is generally easier to maintain in its own method, and therefore Action.
You want to use Security Attributes to restrict access to lock() to certain security groups, yet you want all users to have read access the the Locked state field.
When a resource is locked other fields are also set, like LockedBy and perhaps DateLocked.
While all of that logic could be managed in your single PATCH endpoint logic for the controller, I can't stress enough how this can easily make your solution unmanageable over time or as the complexity of your resource increases.
More importantly: the documented and accepted convention is that PATCH will NOT have side effects, and as such there is no need to execute a GET after a PATCH because the same change on the client has been accepted on the server. Conversely, because a POST MAY have side effects, it is reasonable for the client to expect to execute a GET to get all the related changes if the response from the POST does not contain the updated resource.
In the case of Delete vs PermanentlyDelete now things become personal / opinionated...
By convention, the expectation of DELETE is two fold:
After a delete the resource should no longer appear in collection query results from a GET
After a delete the resource should no longer appear in item requests via GET
From a server point of view, if my resource has a soft delete, that simply sets a flag, and a permanent delete that deletes the record from the underlying store, then by convention I would use an Action called Delete() for the soft delete, and the permanent delete should use the DELETE http verb.
The general reasoning for this is the same as for the discussion about locked().
However, if the intention of soft vs permanent delete is to intercept the client's standard delete workflow, such that the permanent delete concept is hidden or otherwise abstracted in a way that it is not part of the usual workflow (the user has to go somewhere different, like the recycle bin to view deleted records and restore or permanently delete), in that scenario, use the HTTP verb DELETE for soft delete, and make a specific, perhaps collection bound Action to accept the request for permanent delete
This action may have to be unbound, or bound to the collection depending on how you implement your filtering, if we have deleted record 'xyz' such the GET: ~/document('xyz') returns NOT-FOUND then we can't really expect POST: ~/document('xyz')/delete() to execute...

What is the proper HTTP method for modifying a subordinate of the named resource?

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?
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.
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?
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.
RFC 2616 is obsolete. Please read RFC 723* instead, in particular https://datatracker.ietf.org/doc/html/rfc7231#section-4.3.3.

RESTful resource - accepts a list of objects

I'm building a collection of RESTful resources that work like the following: (I'll use "people" as an example):
GET /people/{key}
- returns a person object (JSON)
GET /people?first_name=Bob
- returns a list of person objects who's "first_name" is "Bob" (JSON)
PUT /people/{key}
- expects a person object in the payload (JSON), updates the person in the
datastore with the {key} found in the URL parameter to match the payload.
If it is a new object, the client specifies the key of the new object.
I feel pretty comfortable with the design so far (although any input/criticism is welcome).
I'd also like to be able to PUT a list of people, however I'm not confident in the RESTfulness of my design. This is what I have in mind:
PUT /people
- expects a list of objects in JSON form with keys included in the object
("key":"32948"). Updates all of the corresponding objects in the datastore.
This operation will be idempotent, so I'd like to use "PUT". However its breaking a rule because a GET request to this same resource will not return the equivalent of what the client just PUT, but would rather return all "people" objects (since there would be no filters on the query). I suspect there are also a few other rules that might be being broken here.
Someone mentioned the use of a "PATCH" request in an earlier question that I had: REST resource with a List property
"PATCH" sounds fantastic, but I don't want to use it because its not in wide use yet and is not compatible with a lot of programs and APIs yet.
I'd prefer not to use POST because POST implies that the request is not idempotent.
Does anyone have any comments / suggestions?
Follow-up:::
While I hesitated to use POST because it seems to be the least-common-denominator, catch-all for RESTful operations and more can be said about this operation (specifically that it is idempotent), PUT cannot be used because its requirements are too narrow. Specifically: the resource is not being completely re-written and the equivalent resource is not being sent back from a GET request to the same resource. Using a PUT with properties outside of it's specifications can cause problems when applications, api's, and/or programmers attempt to work with the resource and are met with unexpected behavior from the resource.
In addition to the accepted answer, Darrel Miller had an excellent suggestion if the operation absolutely had to be a PUT and that was to append a UUID onto the end of the resource path so an equivalent GET request will return the equivalent resource.
POST indicates a generic action other than GET, PUT, and DELETE (the generic hashtable actions). Because the generic hashtable actions are inappropriate, use POST. The semantics of POST are determined by the resource to which an entity is POSTed. This is unlike the semantics of the generic hashtable methods, which are well-known.
POST /people/add-many HTTP/1.1
Host: example.com
Content-Type: application/json
[
{ "name": "Bob" },
{ "name": "Robert" }
]
Using PUT is definitely the wrong verb in this case. POST is meant to do exactly what you are asking. From the HTTP specification:
The fundamental difference between the POST and PUT requests is reflected in the different meaning of the Request-URI. The URI in a POST request identifies the resource that will handle the enclosed entity. That resource might be a data-accepting process, a gateway to some other protocol, or a separate entity that accepts annotations. In contrast, the URI in a PUT request identifies the entity enclosed with the request -- the user agent knows what URI is intended and the server MUST NOT attempt to apply the request to some other resource...
As such, if you want to update multiple resources in a single call, you have to use POST.
Just be cause PUT is required to be idempotent and POST is not, does not mean that POST cannot be idempotent. Your choice of HTTP verb should not be based on that, but based on the relationship of the requested resource and the resource acted upon. If your application is directly handling the resource requested, use PUT. If it is acting on some other resource (or resources, as in your case), use POST.
I really don't see any easy way you could use PUT to create an arbitrary set of people. Unless, you are prepared to have the client generate a GUID and do something like,
PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
On the server side you could take the people from the list and add them to the /People resource.
A slight variation to this approach would be to get the server to include a link such as
<link rel="AddList" href="/PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}"/>
in the People resource. The client would need to know that it needs to PUT a list of people to the AddList link. The server would need to make sure that each time it renders the /People resource it creates a new url for the AddList link.
Regarding Darren Miller's suggestion of using PUT to a GUID (I can't comment...), the point of using PUT would be to achieve idempotency for the operation. The litmus test if idempotency would be this conversation between the client and server:
PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
204 NO CONTENT (indicates that it all went well)
client loses connection and doesn't see the 204
client automatically retries
PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
How would the server differentiate the two? If the GUID is "used up" so to speak then the server would have to respond 404 or 410. This introduces a tiny bit of conversational state on the server to remember all the GUIDs that have been used.
Two clients would often see the same I guess, because of caching or simply keeping stale responses around.
I think a smart solution is to use POST to create an (initially empty, short lived) holding area for a resource to which you can PUT, i.e. clients need to POST to create the GUID resource instead of discovering it via a link:
POST /PeopleList/CreateHoldingArea
201 CREATED and Location: /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
PUT /PeopleList/{1E8157D6-3BDC-43b7-817D-C3DA285DD606}
This would mean that the lost idempotency would not result in much overhead; clients simply create new GUIDs (by POSTing) if they didn't see the initial 201 CREATED response. The "tiny bit of conversational state" would now only be the created but not yet used holding areas.
The ideal solution would of course not require any conversational state on the server, but it eludes me.