Imagine a web-application storing some data-resource with some id which stores three attachment (e.g. pdf) per datum.
The URL scheme is
data/{id}/attachment1
data/{id}/attachment2
data/{id}/attachment3
An RESTful API exists for the attachments providing GET/PUT/DELETE operations implementing CRUD operations on the server side.
Letting the id be 123, I would like to perform an operation where
- attachment1 is replaced by a new attachment (such that
GET file/123/attachment1
returns the a new attachment) - attachment2 is deleted (such that that
GET file/123/attachment2
returns 404) - attachment3 remains unchanged.
The update should be atomic - the complete update is performed by the server or nothing at all.
Applying a simple PUT file/123/attachment1
and DELETE file/123/attachment2
is not atomic, since the client could crash after the PUT and the server has no hint that he should do a rollback in this case.
So how do I implement the operation in a RESTful way?
I've thought of two solutions but they both do not seem to be 100% RESTful:
- Use PATCH (could be PUT, but PATCH better reflects the semantics of an partial update) with multipart/form-data on data/123: The multipart/form-data is a sequence of entities consisting of a new "application/pdf" associated with the field "attachment1" and something which would represent a null-value to denote deletion of attachment2.
While this ensures atomicity, I doubt this is RESTful since i overload the PATCH method using different parameter lists, which violates the uniform-interface constraint.
- Use a resource representing a transaction. I could POST the data id 123
to a transaction-URL which would create a transaction resource
representing a copy of the current state of the data-resource stored
on the server, e.g. transaction/data/123. Now i can call PUT and
DELETE on the attachments of this temporary resource (e.g.
DELETE transaction/data/123/attachment2
) and communicate the commit of this version of the resource to the server via a PUT on transaction/data/123. This ensures atomicity while a have to implement additional server side logic to deal with multiple clients changing the same resource and crashed clients which never committed.
While this seems to be consistent with REST it seems to violate the contraint of statelessness. The state of the transactional resource is not service state but application state, since every transactional resource is associated with a single client.
I'm kind of stuck here, so any ideas would be helpful, thanks!