Reputation: 2088
/person/123
(my intent is to update)/person/123
does not existAm I supposed to always allow the client to save (put) the resource, even if it does not exist (i.e. in the DB)?
Possibilities:
No, it is appropriate to restrain the client save action in this case.
Yes. The API must allow the client to save using PUT.
Upvotes: 1
Views: 506
Reputation: 179086
Before jumping on PUT, lets look at what makes PUT different from POST.
The expectation with POST is that it is non-idempotent. This means that calling POST multiple times with the exact same data may result in a different server state than calling it exactly once.
The expectation with PUT is that it is idempotent. This means that calling PUT multiple times with the exact same data should not result in a different server state than calling it exactly once.
Lets look at a couple examples of this:
Imagine a POST request is sent to /person/add
with some data to populate the new person being added. After the first call, the server will have:
[
{ person: 0, ...data... }
]
(JSON syntax used for brevity of example)
Now, imagine the exact same request happens another time or three:
[
{ person: 0, ...data... },
{ person: 1, ...data... },
{ person: 2, ...data... },
{ person: 3, ...data... }
]
In this example, POST is non-idempotent, and the same request resulted in different server states.
Now imagine a PUT request is sent to /person/123
with some data to update the person with an ID of 123
. After the first call the server might have:
[
{ person: 0, ...data... },
...
{ person: 123, ...updated data... }
]
Now, imagine the exact same request happens another time or three:
[
{ person: 0, ...data... },
...
{ person: 123, ...updated data... }
]
In this example, PUT is idempotent, and the same request resulted in the same server states.
Well, there are two choices:
person
with the given ID and populate its dataLets look at the difference in how the requests would be handled
Initial server state:
[
{ person: 0, ...data... }
]
After PUT /person/123 {...new data...}
:
[
{ person: 0, ...data... },
{ person: 123, ...new data... }
]
After PUT /person/123 {...new data...}
multiple times:
[
{ person: 0, ...data... },
{ person: 123, ...new data... }
]
This example shows that there's no real harm here to server state when you create the person
from the data.
Initial server state:
[
{ person: 0, ...data... }
]
After PUT /person/123 {...new data...}
:
[
{ person: 0, ...data... }
]
After PUT /person/123 {...new data...}
multiple times:
[
{ person: 0, ...data... }
]
This example also shows that there's no real harm to server state when you send an error if the person
doesn't exist.
REST isn't a strictly-defined specification that must be followed exactly. It's more like a set of guidelines.
What this means is that it's your call.
If creating a new data set from a PUT request can be done safely, and simplifies your program, there's no harm in allowing it to happen, so long as you do all the same validation and error handling that you'd be doing for a POST request to create a new object.
If creating a new data set from a PUT request is prohibitively difficult or can't be done safely—such as when only some of the data is being updated, and the server can't make a full object—then by all means disallow it and return the appropriate error code (404 Not Found).
Upvotes: 3
Reputation: 13682
You may choose to do either. If you choose the former, then 404 would be appropriate.
Upvotes: 1