Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RESTful copy/move operations?

I am trying to design a RESTful filesystem-like service, and copy/move operations are causing me some trouble.

First of all, uploading a new file is done using a PUT to the file's ultimate URL:

PUT /folders/42/contents/<name>

The question is, what if the new file already resides on the system under a different URL?

Copy/move Idea 1: PUTs with custom headers.

This is similar to S3's copy. A PUT that looks the same as the upload, but with a custom header:

PUT /folders/42/contents/<name>
X-custom-source: /files/5

This is nice because it's easy to change the file's name at copy/move time. However, S3 doesn't offer a move operation, perhaps because a move using this scheme won't be idempotent.

Copy/move Idea 2: POST to parent folder.

This is similar to the Google Docs copy. A POST to the destination folder with XML content describing the source file:

POST /folders/42/contents
...
<source>/files/5</source>
<newName>foo</newName>

I might be able to POST to the file's new URL to change its name..? Otherwise I'm stuck with specifying a new name in the XML content, which amplifies the RPCness of this idea. It's also not as consistent with the upload operation as idea 1.

Ultimately I'm looking for something that's easy to use and understand, so in addition to criticism of the above, new ideas are certainly welcome!

like image 427
ladenedge Avatar asked Jun 10 '10 18:06

ladenedge


3 Answers

The HTTP spec says if the resource already exists then you update the resource and return 200. If the resource doesn't exist then you create it and you return 201.

Edit:
Ok, I misread. I prefer the POST to the parent folder approach. You could also refer to the source file using a query string parameter. e.g.

POST /destination/folder?sourceFile=/source/folder/filename.txt
like image 113
Darrel Miller Avatar answered Oct 21 '22 07:10

Darrel Miller


To create a new resource you usually use POST. This should create a new resource on a URI creates by the Server.

POST /folders/42/contents/fileName
<target>newFile</target>

What REST says is that with POST the new Resource is located in a path determined by the server. This is how copy even works in the (windows) FileSystem. Consider you copy a file to a name that already exists, then the response of the above example could be:

<newFileLocation>/folders/42/contents/newFile-2</newFileLocation>

A move is then made by first copy then delete. You should not do these two actions in one request.

Edit:
I found the book RESTful Web Services Cookbook very good.

Chapter 11 handles the Copy method and recommends the following in 11.1:

Problem You want to know how to make a copy of an existing resource.

Solution Design a controller resource that can create a copy. The client makes a POST request to this controller to copy the resource. To make the POST conditional, provide a one-time URI to the client. After the controller creates the copy, return response code 201 (Created) with a Location header containing the URI of the copy.

Request POST /albums/2009/08/1011/duplicate;t=a5d0e32ddff373df1b3351e53fc6ffb1

Response

<album xmlns:atom="http://www.w3.org/2005/Atom">
<id>urn:example:album:1014</id>
<atom:link rel="self" href="http://www.example.org/albums/2009/08/1014"/>
...
</album>
like image 6
Tarion Avatar answered Oct 21 '22 09:10

Tarion


REST is not limited to the default set of HTTP methods. You could use WebDAV in this case.

like image 5
deamon Avatar answered Oct 21 '22 07:10

deamon