REST - put IDs in body or not? - rest

Let's say I want to have a RESTful resource for people, where the client is able to assign ID.
A person looks like this: {"id": <UUID>, "name": "Jimmy"}
Now, how should the client save (or "PUT") it?
PUT /person/UUID {"id": <UUID>, "name": "Jimmy"} - now we have this nasty duplication that we have to verify all the time: Does the ID in body match the one in path?
Asymmetric representation:
PUT /person/UUID {"name": "Jimmy"}
GET /person/UUID returns {"id": <UUID>, "name": "Jimmy"}
No IDs in body - ID only in location:
PUT /person/UUID {"name": "Jimmy"}
GET /person/UUID returns {"name": "Jimmy"}
No kind of POST seems like a good idea since the ID is generated by the client.
What are the common patterns and ways to solve it? IDs only in location seems like the most dogmatically correct way, but it also makes the practical implementation harder.

There is nothing wrong in having different read/write models: the client can write one resource representation where after the server can return another representation with added/calculated elements in it (or even a completely different representation - there is nothing in any spec against that, the only requirement is that PUT should create or replace the resource).
So I would go for the asymmetric solution in (2) and avoid the "nasty duplication check" on the server side when writing:
PUT /person/UUID {"name": "Jimmy"}
GET /person/UUID returns {"id": <UUID>, "name": "Jimmy"}

If it is a public API you should be conservative when you reply, but accept liberally.
By that I mean, you should support both 1 and 2. I agree that 3 doesn't make sense.
The way to support both 1 and 2 is to get the id from the url if none is supplied in the request body, and if it is in the request body, then validate that it matches the id in the url. If the two do not match, then return a 400 Bad Request response.
When returning a person resource be conservative and always include the id in the json, even though it is optional in the put.

Just FYI, the answers here are wrong.
TLDR; If you're using PUT, you should have the id in the body. If you are using PATCH, you do not need the id in the body.
See:
https://restfulapi.net/rest-api-design-tutorial-with-example/
https://restfulapi.net/rest-put-vs-post/
https://restfulapi.net/http-methods/#patch
PUT
Use PUT APIs primarily to update existing resource (if the
resource does not exist, then API may decide to create a new resource
or not). If a new resource has been created by the PUT API, the origin
server MUST inform the user agent via the HTTP response code 201
(Created) response and if an existing resource is modified, either the
200 (OK) or 204 (No Content) response codes SHOULD be sent to indicate
successful completion of the request.
If the request passes through a cache and the Request-URI identifies
one or more currently cached entities, those entries SHOULD be treated
as stale. Responses to this method are not cacheable.
Use PUT when you want to modify a singular resource which is already a
part of resources collection. PUT replaces the resource in its
entirety. Use PATCH if request updates part of the resource.
PATCH
HTTP PATCH requests are to make partial update on a resource. If you
see PUT requests also modify a resource entity so to make more clear –
PATCH method is the correct choice for partially updating an existing
resource and PUT should only be used if you’re replacing a resource in
its entirety.
So you should use it in this way:
POST /device-management/devices : Create a new device
PUT /device-management/devices/{id} : Update the device information identified by "id"
PATCH /device-management/devices/{id} : Partial-update the device information identified by "id"
RESTful practices indicate that it shouldn't matter what you PUT at /{id}--the content of the record should be updated to the one provided by the payload--but GET /{id} should still link to the same resource.
In other words, PUT /3 may update to payload id to 4, but GET /3 should still link to the same payload (and return the one with id set to 4).
If you are deciding that your API requires the same identifier in the URI and the payload, it's your job to make sure it matches, but definitely use PATCH instead of PUT if you are excluding the id in the payload that should be there in its entirety. This is where the accepted answer got it wrong. PUT must replace the entire resource, where-as patch may be partial.

One solution to this issue involves the somewhat confusing concept of "Hypertext As The Engine Of Application State," or "HATEOAS." This means that a REST response contains the available resources or actions to be performed as hyperlinks. Using this method, which was part of the original conception of REST, the unique identifiers/IDs of resources are themselves hyperlinks. So, for example, you could have something like:
GET /person/<UUID> {"person": {"location": "/person/<UUID>", "data": { "name": "Jimmy"}}}
Then, if you want to update that resource, you could do (pseudocode):
updatedPerson = person.data
updatedPerson.name = "Timmy"
PUT(URI: response.resource, data: updatedPerson)
One advantage of this is that the client doesn't have to have any idea about the server's internal representation of User IDs. The IDs could change, and even the URLs themselves could change, as long as the client has a way to discover them. For example, when getting a collection of people, you could return a response like this:
GET /people
{ "people": [
"/person/1",
"/person/2"
]
}
(You could, of course, also return the full person object for each person, depending on the needs of the application).
With this method, you think of your objects more in terms of resources and locations, and less in terms of ID. The internal representation of unique identifier is thus decoupled from your client logic. This was the original impetus behind REST: to create client-server architectures that are more loosely coupled than the RPC systems that existed before, by using the features of HTTP. For more information on HATEOAS, look at the Wikipedia article as well as this short article.

In an insert you do not need to add the id in the URL. This way if you send an ID in a PUT you may interpreted as an UPDATE to change the primary key.
INSERT:
PUT /persons/
{"id": 1, "name": "Jimmy"}
HTTP/1.1 201 Created
{"id": 1, "name": "Jimmy", "other_field"="filled_by_server"}
GET /persons/1
HTTP/1.1 200 OK
{"id": 1, "name": "Jimmy", "other_field"="filled_by_server"}
UPDATE
PUT /persons/1
{"id": "2", "name": "Jimmy Jr"} -
HTTP/1.1 200 OK
{"id": "2", "name": "Jimmy Jr", "other_field"="filled_by_server"}
GET /persons/2
HTTP/1.1 200 OK
{"id": "2", "name": "Jimmy Jr", "other_field"="updated_by_server"}
The JSON API uses this standard and solves some issues returning the inserted or updated object with a link to the new object. Some updates or inserts may include some business logic that will change additional fields
You will also see that you can avoid the get after the insert and update.

While it's Ok to have different representations for different operations, a general recommendation for PUT is to contain the WHOLE payload. That means that id should be there as well. Otherwise, you should use PATCH.
Having said that, I think PUT should mostly be utilised for updates and the id should always be passed in the URL as well. As a result of that, using PUT to update the resource identifier is a bad idea.
It leaves us in an undesirable situation when id in the URL can be different from the id in the body.
So, how do we resolve such a conflict? We basically have 2 options:
throw a 4XX exception
add a Warning(X-API-Warn etc) header.
That's as close as I can get to answering this question because the topic in general is a matter of opinion.

This has been asked before - the discussion is worth a look:
Should a RESTful GET response return a resource's ID?
This is one of those questions where it's easy to get bogged down into debate around what is and is not "RESTful".
For what it's worth, I try to think in terms of consistent resources and not change the design of them between methods. However, IMHO the most important thing from a usability perspective is that you are consistent across the entire API!

There is nothing bad in using different approaches. but i think the best way is the solution with 2nd.
PUT /person/UUID {"name": "Jimmy"}
GET /person/UUID returns {"id": <UUID>, "name": "Jimmy"}
it is mostly used in this way even the entity framework use this technique when the entity is added in dbContext the class without the generated ID is ID generated by reference in Entity Framework.

You may need to look into PATCH/PUT request types.
PATCH requests are used to update a resource partially whereas in PUT requests, you have to send the entire resource where it gets overridden on the server.
As far as having an ID in the url is concerned, I think you should always have it as it is a standard practice to identify a resource. Even the Stripe API works that way.
You can use a PATCH request to update a resource on the server with ID to identify it but do not update the actual ID.

I'm looking at this from a JSON-LD/ Semantic Web point of view because that's a good way to go to achieve real REST conformance as I have outlined in these slides. Looking at it from that perspective, there is no question to go for option (1.) as the ID (IRI) of a Web resource should always be equal to the URL which I can use to look-up/ dereference the resource.
I think the verification is not really hard to implement nor is it computationally intens; so I don't consider this a valid reason for going with option (2.).
I think option (3.) is not really an option as POST (create new) has a different semantics than PUT (update/ replace).

Related

What HTTP method should i use when i need to pass a lot of data to a single endpoint?

Currently i've asking if the current HTTP method that i'm using on my rest api is the correct one to the occasion, my endpoint need a lot of data to "match" a query, so i've made a POST endpoint where the user can send a json with the parameters, e.g:
{
"product_id": 1
"partner": 99,
"category": [{
"id": 8,
"subcategories": [
{"id": "x"}, {"id": "y"}
]
}]
"brands": ["apple", "samsung"]
}
Note that brands and category are a list.
Reading the mozzila page about http methods i found:
The POST method is used to submit an entity to the specified resource, often causing a change in state or side effects on the server.
My POST endpoint does not take any effect on my server/database so in theory i'm using it wrong(?), but if i use a GET request how can i make it more "readable" and how can i manage lists on this method?
What HTTP method should i use when i need to pass a lot of data to a single endpoint?
From RFC 7230
Various ad hoc limitations on request-line length are found in practice. It is RECOMMENDED that all HTTP senders and recipients support, at a minimum, request-line lengths of 8000 octets.
That effectively limits the amount of information you can encode into the target-uri. Your limit in practice may be lower still if you have to support clients or intermediaries that don't follow this recommendation.
If the server needs the information, and you cannot encode it into the URI, then you are basically stuck with encoding it into the message-body; which in turn means that GET -- however otherwise suitable the semantics might be for your setting -- is out of the picture:
A payload within a GET request message has no defined semantics
So that's that - you are stuck with POST, and you lose safe semantics, idempotent semantics, and caching.
A possible alternative to consider is creating a resource which the client can later GET to retrieve the current representation of the matches. That doesn't make things any better for the first adhoc query, but it does give you nicer semantics for repeat queries.
You might, for example, copy the message-body into an document store, and encode the key to the document store (for example, a hash of the document) into the URI to be used by the client in subsequent GETs.
For cases where the boilerplate of the JSON document is large, and the encoding of the variation small, you might consider a family of resources that encode the variations into the URI. In effect, the variation is extracted from the URI and applied to the server's copy of the template, and then the fully reconstituted JSON document is used to achieve... whatever.
You should be using a POST anyways. With Get you can only "upload" data via URL parameters or HTTP Headers. Both are unsuitable for structured data like yours. Do use POST even though no "change" happens on the server.

What is the most RESTful way to update a resource in a non-idempotent way?

What is the most RESTful way to update part of a resource, where the generation of that resource is done server side, not on the client side. This is not an idempotent action, as the supporting data on the server may change between requests.
I'm creating a Rest API, and I've come to a design choice where I'm quite sure of the way to move forward.
I have a resource that I want to refresh, which involves creating a large json blob based on support data, then saving that json blob to a database before serving it back to the user.
My question is, what is the most RESTful way to perform this action? As the client doesn't perform the calculations, and it also isn't idempotent as the data set may change between each call, I feel it is unnatural to use a PUT.
I settled on a POST, but that doesn't sit right either.
A third option would be to have a sub-resource that describes the action of refreshing - this doesn't feel correct either.
For example, I have a document:
GET /document/<documentId>
which would return something like:
"body": {
"createdAt": "2019-01-01 12:00:00",
"updatedAt": "2019-01-01 13:00:00",
"name": "example",
"location": "example",
"city": "example"
}
These fields are generated by the server when the document is created, the client doesn't update them.
To allow the client to signal that they would like the server to regenerate the document, I have settled on:
POST /document/<documentId>
"body": {
"param1": "updatedparam1",
"param2": "updatedparam2"
}
An alternative approach would be to do something like:
POST /document/<documentId>/refresh
"body": {...}
but that feels more like an RPC call rather than REST.
Does this make sense logically? I haven't seen many suggestions that POST can be to a single resource as opposed to a collection.
Please do let me know if I can expand on anything, I've been banging my head against this for a little while and have probably missed something.
I settled on a POST, but that doesn't sit right either.
POST is fine.
HTTP semantics include rules about invalidating cached representations of resources. Presumably, when you tell the server to regenerate the document, you don't want to keep using the old copy yourself. So the target uri of the request should be the same as that which you use to GET the resource.
So:
POST /document/<documentId>
Is a good start.
An alternative, assuming the semantics match, would be to use PATCH -- that's an appropriate choice to make if what you are doing is proposing replacement values for the representation. In that case, the body of the request should be a "patch document". You can, of course, define your own type of patch document; generic clients may already understand one or more of the standards RFC-6902:JSON Patch or RFC-7386:JSON Merge Patch so you can potentially save some work by supporting one or more of the standard formats.
I haven't seen many suggestions that POST can be to a single resource as opposed to a collection.
Part of the point of REST is that resources support a uniform interface - "single resources" and "collection resources" look the same. Historically, we got a bit unlucky with the early specifications for POST, which were easily misinterpreted as CREATE.
But generic clients don't know, or care, whether or not the resource you specify in a web form is a "collection resource"; it just packs up the data and sends the request, confident that the server will know what to do.

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.

Saving two new related objects in one request

I have two models in Django:
class Thread(models.Model):
entity = models.ForeignKey(Entity, null=True, blank=True)
...
class ThreadMessage(models.Model):
thread = models.ForeignKey(Thread, related_name='messages')
author = models.ForeignKey(User)
...
Now a client wants to create a new thread with first message in it. It has first to do a POST /threads to create a new thread and find out its id and then do POST /messages passing the found id in thread field.
I am thinking if it's reasonable and possible to do all of this in one request from Ember like:
POST /messages
{"message": {"text": "text", ...},
"thread": {"entity": 1}}
And the response would be:
{"message": {"text": "text", "id": 5678, "thread": 1234, ...},
"thread": {"entitity": 1, "id": 1234, ...}}
Yes it is perfectly reasonable.
People seem to interpret REST in a very strange and largely ignorant way. A cursory read of the HTTP RFC 7231 for POST and PUT will confirm you are on solid ground.
A resource representation can represent ANYTHING. The key thing is to preserve the semantics of the REST operations. So PUT can be used for both CREATE and REPLACE like operations (I tend to think of PUT being REPLACE rather than UPDATE as REPLACE is closer to an idempotent semantic than UPDATE in my mind)
A PUT to an endpoint where supported, should accept whatever representation a GET returns. A POST can do literally anything you want as it doesn't need to support idempotent semantics.
HTTP and REST is designed and intended to support resource representations that may overlap other resources and the RFC is explicit about this. You do this all the time when doing a GET on a collection endpoint.
You are NOT breaking REST by having a thread containing a child message in a single request and IMO that is a very valid use use case for sane referential integrity on the server. Any time a transactional semantic is required, a POST or PUT is perfectly valid to create a graph of objects on the server in a single request. It is really simple, if you can GET it in a single request, you should be able to PUT it in a single request, so think carefully about your URL's and parameters.
For example, you may have a thread endpoint that returns all messages and that endpoint may support a parameter to just return some subset of the information /api/threads?include=hasRead which returns just id and hasRead for each message in the thread, or perhaps just some range of 'pages'. You can then PUT using that same endpoint and parameters and just update thehasRead property in bulk.
Anyone who gets hung up on this has probably never considered access controls either. Access control necessitates a different view of a resource from one user to another based on what they are allowed to access. This different view of a resource is conveyed in HTTP auth headers and/or in the request URL; again REST is not being broken by sub-setting or overlapping resources.
So go ahead and create the minimal graph of objects you need and either PUT or POST them. I use V4 UUID's so clients can assign ID's (and thus resource endpoints) themselves and this allows me to use PUT for both create and replace like actions and wire up complex object graphs without client<->server id mapping issues.
What you are trying to do will be break concept of REST and EmberJS itself.
If you have two separate APIs you should make two REST calls.
First save the parent thread model , after successful return save the child message. Then use addObject to reflect changes in views.
This is best way. Don't try to optimize by reducing API calls here and breaking REST in the way.

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.