REST API design for cloning a resource

10,668

Solution 1

Influenced by project requirements and the range of preferences amongst members in my team, option 1 will serve us best at this stage.

  • Conforming to the standard HTTP methods will simplify and clarify my API
  • There will be a single, consistent approach to cloning a resource. This outweighs the issue I have with designating the cloning work to the consumer.

Solution 2

Most of these options are perfectly good choices. A lot of it just your style choice in the end. Here are my comments on each of your options.

  1. Relinquishing the responsibility of cloning the resource object to the consumer
    In general I don't really have a problem with this solution. This option is very straight forward for a user to understand and implement. It might be better than coming up with some proprietary cloning functionality that your users have to learn how to use.

  2. Using the WebDAV HTTP extensions which provides a COPY method
    I like to stick to the standard methods as well. I would not use COPY, but I wouldn't appalled if you did.

  3. POSTing to /{resource}?resourceIdToClone={id}
    This is a perfectly good solution. From a REST standpoint, you don't really have a conflict with the rest of your API. The URI with a query parameter identifies a different resource than the URI without the query parameter. Query parameters are a URI feature for identifying resources that you can not be referenced hierarchically. However, it might be difficult to separate these in your code because of the way most REST frameworks work. You could do something similar to this except with a hierarchical URI such as /{resource}/clone. You could POST to this URI and pass the resource_source_id in the body.

  4. Adding a new resource called 'CloneableResource' and performing a POST to /CloneableResource/{resource_type}/{resource_source_id}
    There is nothing wrong with this approach from a REST standpoint, but I think adding a new type is both unnecessary and clutters the API. However, I disagree with your intuition there could be problem with having a resource that has only a POST operation. It happens. In the real world, not everything fits nicely into GET, PUT, or DELETE.

  5. A GET against /resource/{id}?method=clone
    This is the only option of the 5 that I can not condone. It seems from your description that you already understand why this is a bad idea, so I'm not sure why you are considering it. However, all you have to do to make this a good solution is to change GET to POST. It then becomes very similar to the #3 solution. The URI could also be hierarchical instead of using a query parameter. POST /resource/{id}/clone would work just as well.

I hope this was helpful. Good luck with your decision.

Solution 3

If you want to COPY a resource, then, yes, COPY is an obvious choice.

(and yes, it would be good to pull the definitions of COPY and MOVE out of RFC 4918 to untangle them from WebDAV).

Share:
10,668
dev'd
Author by

dev'd

Updated on July 24, 2022

Comments

  • dev'd
    dev'd almost 2 years

    I am writing a YAML document using swagger to design a RESTful API method for cloning a resource. I have a few options and don't know which would be best. Please can someone advise?

    Options:

    1. Relinquishing the responsibility of cloning the resource object to the consumer (where the consumer assigns values to properties on a new object and then creates a new object), the process would need to consist of two requests to the API: a GET against a resource for the source object and then a POST to that resource for creating the new one. This feels like the consumer has too much responsibility.
    2. Using the WebDAV HTTP extensions which provides a COPY method (see here). It would appear that this is exactly what I would like for cloning. However, I would like to stick to the standard methods as much as possible
    3. POSTing to /{resource}?resourceIdToClone={id} where resourceIdToClone is an optional parameter. This would conflict with an API path that I already have for creating the resource, where I add a schema to the POST body. It would mean using a POST to /{resource}/ for creating and cloning, and that would violate SRP.
    4. Adding a new resource called 'CloneableResource' and performing a POST to /CloneableResource/{resource_type}/{resource_source_id}. For the example of cloning a sheep, you'd make a POST to /CloneableResource/Sheep/10. This way, it would be possible to stick to using the standard HTTP methods, there'd be no conflict with any other resource paths (or SRP violation). However, I would be adding a new and potentially superfluous type to the domain. I also can't think of a scenario when a consumer would want to perform anything other than a POST to this resource, so it seems like a code smell to me.
    5. A GET against /resource/{id}?method=clone. One of the advantages here is that no additional resource is required and it may be determined by a simple optional querystring parameter. I'm aware that one of the risks here is that it can be dangerous to provide post or delete capabilities using a GET method if the URL is in a web page as it may be crawled by a search engine.

    Thanks for any help!

  • dev'd
    dev'd almost 9 years
    Thanks for your response Julian. This is a convenient option and there is no doubt about what the method allows the consumer to do. However, I believe that sticking to standard HTTP methods is the best way forward for now because it would simplify my API and avoid a scenario where it's possible to achieve the same outcome in two different ways (cloning a resource either by using COPY, or by doing a GET against a resource then a POST). I'd prefer to restrict the consumer to only a single, consistent method of achieving a resource clone via my API
  • dev'd
    dev'd almost 9 years
    Thanks for your consideration Jason. It's more and more apparent that there's no 'right' answer here. Hopefully this brief discussion will help others in future.