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.
For the move part, just do a combo of Copy (PUT) then Delete if you want to keep it simple.
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.
Related
First of all, i would like to Thank #Darrel Miller. The below question raised from his answer in RESTful copy/move operations?.
I am trying to construct a restFul service, with multiple resource and one resource in that is - for copying file from one location to another location under same parent directory.
Here are my confusion:
Which method to choose for it? POST or PUT.
Can we go with URL Params or through Payload?
If it is URL Params how it should looks like?
And if suppose i need to do this for list of files, Is it still good to go with URL Params?
These are my params
sourceLocation
destLocation
fileName
Thanks in advance!
I was reading this answer, and it says this:
When dealing with a Member URI like:
http://example.com/resources/7HOU57Y
...
POST: Treats the addressed member as a collection in its own right and creates a new subordinate of it.
...
I've googled for this and found lots of results that say this exact quote, but none of them explain what it means. Can someone elaborate and use examples?
Bogdan's answer is correct on what the answer you refer to means, but that answer is a little misleading, because REST is not CRUD with HTTP. POST is not a synonym for Create.
The semantics of the POST method is to do any action that isn't already standardized by the HTTP protocol. POST is the only method that submits the payload to be processed by the targeted resource itself, not by the server. In a way, you can say that with the GET, PUT, PATCH and DELETE methods, the resource isn't aware of what's happening to itself, the server does the whole job, but with POST, the server has to ask the resource to do something.
This means that any action using a POST method must be documented in some way. The clients can assume a GET, PUT, PATCH and DELETE request will follow the RFC 7231, but the final result of a POST will depend on the target media type.
So, if the documentation for the media-type of the resource at http://example.com/resources/7HOU57Y says that a POST will create a subordinate resource and return the URI, fine, that's what it should do. If the documentation says that a POST will launch nuclear missiles against targets in Russia, then that's what it should do. If there's no documentation, someone made a mistake.
You can use POST to create a resource when you don't know what ID to give it. So you POST it to a resource that acts as a builder of such resources, and the server allocates an ID.
POST to http://example.com/resources and a new resource is created and the server gives it ID 7HOU57Y. You get http://example.com/resources/7HOU57Y.
The new resource is a subordinate of the collection, like a file is to a directory, for example.
But if POST works like this, then POSTing to http://example.com/resources/7HOU57Y should get me a new resource subordinated to this one, like http://example.com/resources/7HOU57Y/XYZ.
This is what I understand from that answer you posted. Of course this is highly dependent on how your service works (e.g. I could specify POST as unsupported for resources like http://example.com/resources/7HOU57Y).
I must fulfill a web service with PUT as method to send changes. This service is used to change configurations. So, for example, if I send {"varA":true} to url/configurationchageit sets the corresponding variable, and if I send {"varB":true} it changes varB without affecting varA.
I always though that PUT (and searching google it seems as if I am right) just overwrites the resource (or creates it if not existing). Which I think would mean that I always have to send all variables, or the ones that are not sent will be deleted. So, is the behavior of this web service correct??
WITH EXAMPLES
PUT {"varA":true}
Resource content: {"varA": true}
PUT {varB:true}
happening: Resource content: {"varA": true, "varB":true}
what I think should happen: Resource content: {"varB":true}
No, it's not. You probably want to look at the PATCH method instead (see http://greenbytes.de/tech/webdav/rfc5789.html)
I am not that new to web service but I am not able to understand use of http methods type in restful web service.
I was referring to vogella tutorial here
http://www.vogella.com/tutorials/REST/article.html#rest_httpmethods
They have following description that I am not able to understand somewhat
GET defines a reading access of the resource without side-effects. The resource is never changed via a GET request, e.g., the request has no side effects (idempotent).
(This is fine. No query here)
PUT creates a new resource. It must also be idempotent.
(Ok seems logical, but it must be idempotent why should I care about it? I am not going to call again this service with same data.)
DELETE removes the resources. The operations are idempotent. They can get repeated without leading to different results.
(Ok same question again why do I want to repeat delete query once it is already deleted?)
POST updates an existing resource or creates a new resource.
(This is fine)
I can do delete and putting data with get and post method also, I know I am not able to understand, but why should I use extra method type delete and put, that are provided in web services and what is exactly use for that ?
The most widely used and "known" HTTP methods are GET and POST. But there are other methods, each of which have different semantics. We need to choose the method which has te most proper meaning to the operation the request is meant to perform, and should not "dumb down" the semantics for those only familiar with GET and POST.
DELETE. The semantics are as follows. Once a DELETE request has been processed for a given resource, that resource can no longer be accessed be clients, no ifs, ands, or buts. Any future request to try and retrieve this resource state's representation with GET or HEAD should result in a 404.
That being said, if the semantics of the operation fit the above description, we must use DELETE. Anything less, such as a "soft" delete or some other state-changing interaction, should not be done with a DELETE, better with POST. So it comes down to the semantics, why to use DELETE.
As far as the question "why do I want to repeat delete query once it is already deleted?", well we don't, but if we were to try to use the exact same DELETE request again, it would have the same effect. That is the meaning of idempotency. It really has no bearing on the why. It is just guaranteed protocol semantics
PUT. It's basically used to update a server resource, or create a user resource. In both cases, the URI is known by the user and is the requested URI. For example
PUT /customers/1234
// some body with name to change
The resource URI is known and the client post a message with a representation to update the resource. If the requested operation meats these requirements, then PUT should be used. In contrast if we are creating a new server resource (customer), then we would use POST
POST /customer
// customer representation
Notice the URI of the new customer is not known, because it has not been created. If the POST id successful, we should be back a Location header with the new URI
HTTP/1.1 201
Location: /customers/12345
That was going a little off on a tangent, but getting back to PUT. PUT is idempotent, because no matter how many times we make the exact above PUT request, the result will be the same. No server state will be affected. On the other hand, if we repeated make the same POST request, more new customer may be created
All that being said, we should do out best to follow the protocol semantics. POST is like a wild card for operations that can't be applied to any other method semantics.
And to answer your repeated question, "why should i care?", as noted about DELETE, idempotency is just a matter of guaranteed protocol semantics, it is not a matter of "but i never plan to do this opertion again", it's a matter of "if someone does perform this exact operation again, there is no effect"
There are mainly four methods are used in restful api.they are:
GET-Used to get some resources
POST-Used to create resource
DELETE-Used to remove resource
PUT-Used to update resource.
As you mentioned above we can use post or get for the purpose of put and delete functions.But in programming we can use this method in place where it indicate its purpose so that others will get an idea of what the code is doing
I'm curious to learn more about RESTful design patterns around the PUT call. Specifically, am I violating norms by changing the resource ID as part of a PUT call?
Consider the following...
POST /api/event/ { ... } - returns the resource ID (eventid) of the new event in the body
GET /api/event/eventid
PUT /api/event/eventid - returns the (possibly new) resource ID depending on request body
GET /api/event/eventid - fails if the original eventid was used in the URI
The endpoints for GET and PUT can quickly access the resource if the eventid represents internal resources (like a database record). If the PUT results in the server moving the underlying resource, the ID can change.
Am I violating norms when I do this?
REST is not a strict specification, but more a set of guidelines and best practices that can be followed to build web-services that are easy to understand and work with. So there's nothing that prevents you from changing a resource IDs during a PUT.
That being said, doing so is IMO a bad practice. One of the ideas behind REST is that each resource can be referenced using a URI. In your case this URI is the concatenation of the path and (I assume) an internal ID. This URI could be used by other "systems" and stored as references. If you change the ID of a resource on a PUT, you change the URI and all references to that resource will be broken (404).
If you feel the need to change the ID that is part of the URI, you may not have picked the right property for it. Consider something else that would be immutable (e.g.: tag your resource with a UUID and use it rather than an internal DB ID).
Not addressing your question full on, but this makes me worry:
returns the resource ID (eventid) of the new event in the body
You aren't returning an integer id, and then letting the client construct urls from this, are you? A proper REST application should give url's to resources, not ids.
As for your question - PUT means something like "Create a new resource at this location". You could conceivably reply with a redirect and a Location header, but it's a bit of a strange thing to do. Besides, the semantics of PUT dictates that you send the entire entity with the request, which is probably not what you want in this scenario. Maybe it would be more fitting to use POST in this situation? (E.g. POST on /api/event/1234
I think it's ok; PUT is still idempotent (repeated calls will not lead to other modifications).
Just: I would ensure that the old ID is not reused, and have the api return 301 codes for calls to old ID (in case other clients had links to the resource).
Maybe the initial PUT that modifies the ID should return a 303 code that point to the new resource location, I'm not sure here.