What is the restful way to represent a resource clone operation in the URL?

Since there is no copy or clone method in HTTP, it's really up to you what you want to do. In this case a POST seems perfectly reasonable, but other standards have taken different approaches:

  • WebDAV added a COPY method.
  • Amazon S3 uses PUT with no body and a special x-amz-copy-source header. They call this a PUT Object - Copy.

Both of these approaches assume that you know the destination URI. Your example seems to lack a known destination uri, so you pretty much must use POST. You can't use PUT or COPY because your creation operation is not idempotent.

If your service defines POST /resources as "create a new resource", then why not simply define another way to specify the resource other than as the body of the POST? E.g. POST /resources?source=/resources/10 with an empty body.


Francis' answer is a great one and probably what you're looking for. With that said, it's not technically RESTful since (as he says in the comments) it does rely on the client providing out of band information. Since the question was "what is the restful way" and not "what is a good way/the best way", that got me thinking about whether there is a RESTful solution. And I think what follows is a RESTful solution, although I'm not sure that it's necessarily any better in practice.

Firstly, as you've already identified, GET followed by POST is the simple and obvious RESTful way, but it's not efficient. So we're looking for an optimization, and we shouldn't be too surprised if it feels a little less natural than that solution!

The POST + sourceId solution creates a special URL - one that points not to a resource, but to an instruction to do something. Any time you find yourself creating special URLs like that, it's worth considering whether you can work around the need to do that by simply defining more resources.

We want the ability to copy

resources/10

What if we come up with another resource:

resources/10/copies

...and the definition of this resource is simply "the collection of resources that are copies of resource/10".

With this resource defined, we can now re-state our copy operation in different terms - instead of saying "I want the server to copy resources/10", we can say "I want to add a new thing to the collection of things that are copies of resources/10".

This sounds strange, but it fits naturally into REST semantics. For instance, let's say this resource currently looks like this (I'm going to use a JSON representation here):

[]

We can just update that with a POST or PATCH [1]:

POST resources/copies/10
["resources/11"]

Note that all we're sending to the server is metadata about a collection, so it's very efficient. We can assume that the server now knows where to get the data to copy, since that's part of the definition of this resource. We can also assume that the client knows that this results in a new resource being created at "resources/11" for the same reason.

With this solution, everything is defined clearly as a resource, and everything has one canonical URL, and no out-of-band information is ever required by the client.

Ultimately, is it worth going with this strange-feeling solution just for the sake of being more RESTful? That probably depends on your individual project. But it's always interesting to try and frame the problem differently by creating different resources!

[1] I don't know if makes sense to allow GET on "resources/10/copies". Obviously as soon as either the original resource or a copy of it change, the copy isn't really a copy any more and shouldn't be in this collection. Implementation-wise, I don't see the point in burdening the server with keeping track of that, so I think this should be treated as an update-only resource.

Tags:

Rest