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!
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
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>
REST is not limited to the default set of HTTP methods. You could use WebDAV in this case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With