简体   繁体   中英

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!

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> 

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. eg

POST /destination/folder?sourceFile=/source/folder/filename.txt

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

For moving, you could

a). copy via PUT with a custom source header followed by a DELETE on the source.

b). DELETE source with a custom move header.

I prefer the latter because it can be atomic and it is clear to the client that the resource was removed from the original collection. And when it GETs the collection of its new location, it will find the moved resource there.

对于移动部分,只需要复制(PUT)然后删除组合,如果你想保持简单。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM