Imagine an HTTP REST endpoint, ...
According to Fielding himself
There is no such thing as a REST endpoint. There are resources. A countably infinite set of resources bound only by restrictions on URL length. (Source)
So technically this is idempotent, which usually leans toward either PUT or PATCH ...
Idempotency is an important property to a client in regards to temporary network issues which allows it to automatically resend the request in case it did not receive a response within a reasonable amount of time. In such a case a client does not know whether the initial request received the server at all or just the response got lost. Idempotency has nothing to do with your demand to only allow to write to a resource only once. In addition to that, PATCH
is not idempotent by default. Idempotent just means that processing a request always results in the same outcome, regardless how many times you send that request to the server.
Each individual message is identified by a unique identifier, such as a GUID value of some sort
... each distinct message is to be uniquely identified by its id field, and that if another message is sent with the same id, it is simply considered a duplicate.
A resource always is uniquely identifiable via its URI as a URI itself can only reference one single resource. A single resource however may have multiple URIs, i.e. one with an other without query parameters available. URI is an abbreviation for uniform resource identifier, where uniform denotes to remaining the same in all cases and at all times. This makes the requirement for the id field in my opinion redundant.
As far as I understood your question, the actual text of the message does not define whether a message is a duplicate or not. So basically
PUT /messages/eaff31bd-5291-4287-a7dd-fbe5b1e47b67 HTTP/1.1
Host: www.acme.com
Content-Type: application/json; charset="utf-8"
...
{
"text": "original text"
}
and
PUT /messages/eb1db214-d231-4a50-916c-8de2d64c7d3a HTTP/1.1
Host: www.acme.com
Content-Type: application/json; charset="utf-8"
...
{
"text": "original text"
}
are requests for two different messages as they target different resources, while you don't want to allow something like
PUT /messages/eaff31bd-5291-4287-a7dd-fbe5b1e47b67 HTTP/1.1
Host: www.acme.com
Content-Type: application/json; charset="utf-8"
...
{
"text": "amended text"
}
as this would update an existing message.
In such a case I'd disable PUT
completely for messages by not supporting it while allowing the creation of new messages only via POST
. A request/response sample may look like this:
POST /messages HTTP/1.1
Host: www.acme.com
Content-Type: application/json; charset="utf-8"
Accept: application/json
...
{
"text": "Some other text"
}
which may yield a response such as:
HTTP/1.1 201 Created
Content-Type: application/json; charset="utf-8"
Location: http://www.acme.com/messages/740177d2-1de9-41bd-bd5b-6a52f39bf227
Etag: 33a64df551425fcc55e4d42a148795d9f25f89d4
{
"text": "some other text"
}
Attempting to update such a resource via
PUT /messages/740177d2-1de9-41bd-bd5b-6a52f39bf227 HTTP/1.1
Host: www.acme.com
Content-Type: application/json; charset="utf-8"
Etag: 33a64df551425fcc55e4d42a148795d9f25f89d4
{
"text": "updated text"
}
should result in a
HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD
response, which states that a server knows the indicated PUT operation but does not support that operation on the target resource. The mandatory Allow
header furthermore teaches your client about the valid HTTP operations supported by that resource.
For the purposes of this question, assume that the route used is always of the form /.../message, never of the form /.../message/{id}. In that case, I am wondering if being restricted to the /.../message route scheme automatically means POST should be used.
In such a case PUT
is not an option for you unless that request contains all the messages that should be available after the request was processed. The semantics of PUT are defined as replacing the current representation stored on the target resource with the one provided in the request payload. So, if you send a PUT request to a "collection resource" you'd technically replace all of the messages currently available with the ones defined in the request.