Reputation: 136637
Part of our RESTful API will allow users to register an item with a serial number. As the serial number is not globally unique it cannot be used as the identifier of the resource, so we'll use a POST to the parent resource which will generate an identifier, e.g.
POST /my/items
<item serial-number="ABCDEF" />
In the case where the item is not already registered, the HTTP semantics are well defined. We return a Location header, and the registered item as the entity body, e.g.
HTTP 201 Created
Location: /my/items/1234
<item id="1234" serial-number="ABCDEF" />
However, in the case where the item is already registered, the API should be idempotent and return the previously registered item without creating a new one. My best guess is that it should then return a 200 OK status code, and use the Content-Location header to indicate where the item actually came from, e.g.
HTTP 200 OK
Content-Location: /my/items/1234
<item id="1234" serial-number="ABCDEF" />
Would this seem reasonable? I'm not entirely clear whether the Location or Content-Location is more suitable in the second case.
Upvotes: 6
Views: 1904
Reputation: 16438
I had similar requirement recently. For idempotent operations PUT is the best way. You're right there is a mismatch between the external-id and the internal one. I solved it by creating a dedicated resource for the external id target:
PUT /api-user/{username}/items/{serialNumber}
Internally I resolve it as a CREATE in case I have no item for 'username' and 'ABCDEF' serial number or UPDATE in case I do.
In case it was a CREATE I return 201 for an UPDATE 200. Further more the returned payload contains both homegrown id and the external serial number like you suggested in your payload.
Upvotes: 7
Reputation: 142094
Here is an interesting discussion on usages of the two headers. It claims Content-Location is not defined for PUT or POST so Location is possibly the better option in your case. It is certainly not clear cut which is better though.
Overall I think your approach makes sense though.
Upvotes: 1