13

I have a RESTful web service which represent processes and activities. Each activity is inside one and only one process. I would like to represent a "move" operation of activity between the process it is currently in and another process.

I've look at forums and found people suggest to use MOVE operation which is not very standard and other suggest to use PUT but then I'm not sure how to tell the difference between PUT that update and PUT that moves which looks semantically wrong.

Any ideas?

Ido Ran
  • 10,584
  • 17
  • 80
  • 143

3 Answers3

11

One way might be to represent the move itself as, say, a "transfer" resource (transfer as a noun), and POST a new one:

POST /transfer

With an entity containing:

activity: /activities/4
toProcess: /processes/13

This way, clients are creating new "transfers" which, on the server, handle validating and transferring the activity.

This gives you the ability to add information about the transfer, too. If you wanted to keep a history for auditing, you could add a transferredBy property to the resource, or a transferredOn date.

Rob Hruska
  • 118,520
  • 32
  • 167
  • 192
  • Hi, This is interesting idea. I've not thought on using the transfer itself as resource but I guess that is what REST is all about. You think it is good that by creating (posting) a new transfer resource another resource will be changed? – Ido Ran Jun 29 '11 at 11:05
  • 1
    Yes, that's perfectly fine. POST does not have to be [idempotent](http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.2), so it can have side-effects. – Rob Hruska Jun 29 '11 at 11:23
  • +1. This is the way I've also thought of. I think this is cleaner than a PUT on the contained element whenever the move should affect both, the container (its listing of contained elements) and the contained element (its parent link field). However, I'm wondering if REST is about being clean in that sense. Is it ok to assume somebody else PUTs on the parent whenever we PUT on the child? Or should we care about being RESTfully correct even when looking at the complete set of actual requests made by any client? – Jo So Nov 15 '13 at 14:49
  • I don't think having two separate PUTs violates REST, but it does make for a more cumbersome API and makes more work for the client to ensure the transactionality of the operation. It mainly just depends on how clients need to interact with the system, and which way works best for that interaction. – Rob Hruska Nov 15 '13 at 15:01
  • This approach is best suited to long running jobs, as a success response means that the job has been added to the queue. The client then has the option to query the server for job progress or status. If moving the resource however means essentially changing a column in a database, I would go with a simpler approach like directly using PUT to update the activity resource. – elolos Jan 18 '16 at 11:07
  • [A PUT request applied to the target resource can have side effects on other resources](https://tools.ietf.org/html/rfc7231#section-4.3.4) – Roman Vottner Sep 13 '18 at 17:08
5

If using PUTs, you can tell the difference by whether the process of the existing entity matches the new one.

PUT /process1/activity2

process: 2
some_data: and_stuff

To which the logical response (if successful) is

303 See Other
Location: /process2/activity2
OrangeDog
  • 36,653
  • 12
  • 122
  • 207
  • You might also want to use "204 No Content" instead of the 303: http://grzegorzborkowski.blogspot.nl/2009/04/relocating-resources-with-restful-web.html – mb21 Jul 16 '14 at 13:20
  • 1
    What would happen if you `PUT` a second time? Doesn't seem like `PUT` is [idempotent](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT) as it should be for a RESTful api. – ahong Sep 13 '18 at 16:13
  • @ahong you should get a `404 Not Found` and no change of state. That would be idempotent. – OrangeDog Sep 13 '18 at 16:53
  • Perhaps a more RESTful implementation would be to use `PUT` like a copy command (idempotent), and then delete afterwards, like in this answer: https://stackoverflow.com/a/6709383 – ahong Sep 13 '18 at 16:55
  • @OrangeDog I'm not sure that's idempotent if you get a 303 for the first response and then a 404 for the second. Something has changed at the URI. – ahong Sep 13 '18 at 16:57
  • 2
    @ahong idempotency is a property of the transmission, not the state! There is no guarantee that between two `PUT` commands a third party updates the resource to something different. Idempotency just guarantees that in case of a network issue i.e. the request can be resent without any further considerations as the outcome will be the same for both of the requests – Roman Vottner Sep 13 '18 at 17:00
  • @ahong idempotence has nothing to do with what the response is, it's only concerned with the state of the system. If you repeat a request N times (and no other state changes occur) then the state should be the same as if you'd only done it once. This answer satisfies that. – OrangeDog Sep 13 '18 at 17:00
  • Fair enough about the response. From all the answers I've seen, it seems difficult to find a good way to move something in a RESTful way. See [RFC 7231, section 4.3.4 on PUT](https://tools.ietf.org/html/rfc7231#section-4.3.4) _A successful PUT of a given representation would suggest that a subsequent GET on that same target resource will result in an equivalent representation being sent in a 200 (OK) response._ In this case, a subsequent GET would return a 404. Not saying being RESTful is the most important thing, but if we must, I think PUT (copy) and DELETE would satisfy the above. – ahong Sep 13 '18 at 17:12
  • @ahong you are misinterpreting the standards. My solution returns a 303 status, not a 2xx, so clearly trying to GET the resource on the original URL is incorrect behaviour. – OrangeDog Sep 13 '18 at 17:29
  • @RomanVottner agreed that between 2 puts, something else may happen. I'm sure we actually agree, and maybe this is just semantics, but I'm not sure if it's only a _property of transmission_. As it states in the [definition of idempotency of an HTTP Method](https://developer.mozilla.org/en-US/docs/Glossary/Idempotent): _An HTTP method is idempotent if an identical request can be made once or several times in a row with the same effect while leaving the server in the *same state*_. Emphasis mine. – ahong Sep 13 '18 at 17:31
4

Given the available answers I'm not really satisfied with the proposals.

POST is an all purpose method that should be used if none of the other operations fit the bill. The semantics of a payload received are defined by the service/API only and may therefore a solution for one API but not for most ones. It further lacks the property of idempotency which in case of a network issue will leave the client in an uncertainty whether the request received the server and only the response got lost mid way or if the request failed to reach the server at all. A consecutive request might therefore lead to unexpected results or further actions required.

PUT has the semantics of replace the current representation obtainable from the resource (may be empty) with the representation provided in the payload. Servers are free to modify the received representation to a more fitting one or to append or remove further data. PUT may even have side effects on other resources as well, i.e. if a versioning mechanism for a document update is provided. While providing the above-mentioned idempotency property, PUT actually does not fit the semantics of the requested action. This might have serious implications on the interoperability as standard HTTP servers wont be able to server you correctly.

One might use a combination of POST to create the new representation on the new endpoint first and afterwards remove the old one via DELETE. However, this are two separate operations where the first one might fail and if not handled correctly lead to an immediate deletion of the original resource in worst case. There is no real transactional behavior in these set of operations unfortunately.

Instead of using the above mentioned operations I'd suggest to use PATCH. PATCH is a serious of changes calculated by the client necessary to transform a current representation to a desiered one. A server supporting PATCH will have to apply these instructions atomically. Either all of them are applied or none of them at all. PATCH can have side effects and is thus the most suitable fit to perform a move in HTTP currently. To properly use this method, however, a certain media-types should be used. One might orientate on JSON Patch (more reader-friendly) i.e., though this only defines the semantics of operations to modify state of JSON based representations and does not deal with multiple resources AFAIK.

Community
  • 1
  • 1
Roman Vottner
  • 12,213
  • 5
  • 46
  • 63