I'm well into implementing a REST service (on a Windows CE platform if that matters) and I started out using IBM's general definitions of using POST for creating (INSERTs) and PUT for updating.
Now I've run across Sun's definitions which are exactly the opposite. So my question is, which is the "generally accepted" definition? Or is there even one?
The disadvantage of using PUT to create resources is that the client has to provide the
unique ID that represents the object it is creating. While it usually possible for the client
to generate this unique ID, most application designers prefer that their servers (usually
through their databases) create this ID. In most cases we want
our server to control the generation of resource IDs. So what do we do? We can switch
to using POST instead of PUT.
So:
Put = UPDATE
Post = INSERT
The reason to use POST as INSERT and PUT as UPDATE is that POST is the only nonidempotent and unsafe operation according to HTTP. Idempotent means that no matter how many times you apply the operation, the result is always the same. In SQL INSERT is the only nonidempotent operation so it should be mapped onto POST. UPDATE is idempotent so it can be mapped on PUT. It means that the same PUT/UPDATE operation may be applied more than one time but only first will change state of our system/database.
Thus using PUT for INSERT will broke HTTP semantic viz requirement that PUT operation must be idempotent.
The verbs are:
GET {path}: Retrieve the resource whose identifier is {path}.
PUT {path}: Create or update the resource whose identifier is {path}.
DELETE {path}: Delete the resource whose identifier is {path}.
POST {path}: Invoke an action which is identified by {path}.
When the intention is to create a new resource, we can use PUT if we know what the identifier of the resource should be, and we can use POST if we want the server to determine the identifier of the new resource.
PUT can be used for creation when the server grants the client control over a portion of its URI space. This is equivalent to file creation in a file system: when you save to a file that does not yet exist you create it and if that file exists the result is an update.
However, PUT is lacking the ability of an implicit intent of the client. Consider placing an order: if you PUT to /orders/my-new-order the meaning can only ever be update the resource identified by /orders/my-new-order whereas POST /orders/ can mean 'place a new order' if the POST accepting resource has the appropriate semantics.
IOW, if you want to achieve anything as a side effect of the creation of the new resource you must use POST.
Jan
We use POST= Create, PUT= Update.
Why? There's no good reason. We had to choose one, and that's that choice I made.
Edit. Looking at other answers, I realize that the key creation issue might make the decision.
We POST new entries and return a JSON object with the generated key. It seems like this is a better fit for generally accepted POST semantics.
We PUT to existing entries with a full URI that identifies the object.
Here http://www.w3.org/Protocols/rfc2616/rfc2616.html is the offical guide of how to implement the behaviour of the HTTP methods.
I've been studying the concepts and implementations of REST a lot lately and the general consensus seems to be: PUT is used for creating/updating depending on whether or not the resource already exists. POST is used to append a resource to a collection.
See HTTP/1.1 Method Definitions http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
POST is designed to allow a uniform method to cover the following
functions:
- Annotation of existing resources;
- Posting a message to a bulletin board, newsgroup, mailing
list, or similar group of articles;
- Providing a block of data, such as the result of submitting a
form, to a data-handling process;
- Extending a database through an append operation.
The PUT method requests that the enclosed entity be stored under the
supplied Request-URI. If the Request-URI refers to an already existing
resource, the enclosed entity SHOULD be considered as a modified
version of the one residing on the origin server.
Also see the accepted answer to the question at Understanding REST: Verbs, error codes, and authentication.
Related
I like the idea of vectorized/batched requests similar to what the StackExchange API offers and would like to implement something for my own API, i.e. GET /users/1;2;3;4;5 would return the selected user resources with id 1 to 5.
I think this is fairly simple when reading data, but what would be the expected behavior for i.e. a POST request to a subresource?
POST /1;2;3;4;5/subresource
Would this mean:
Creation of five new subresources, assigned to each id (1:1)
Creation of a single new subresource, but assigned to each resource id (1:n)
I have a couple of concerns regarding this approach. First, resources should be uniquely addressable via certain resource locators (URIs). Using your approach however bypasses this requirement in some way IMO. This approach may also lead to other issues later on, i.e. plenty of frameworks do not allow URIs that exceed a certain character size.
Furthermore, instead of consecutive resource IDs the resource should use UUIDs instead. This will first and foremost prevent guessing attacks and also prevent logical issues on moving resources or inserting some in between.
The POST method requests that the target resource process the
representation enclosed in the request according to the resource's
own specific semantics.
In regards to HTTP POST operations, the specification clearly states that the semantics of any body received via POST is up to the service developer. So you are basically allowed to do anything within a POST request. As the semantics is totally up to you, you have to document the behavior explicitely. Not documenting the applied logic will leave a large grey-zone for service users.
While the HTTP 1.1 spec seems to allow message bodies on DELETE requests, it seems to indicate that servers should ignore it since there are no defined semantics for it.
4.3 Message Body
A server SHOULD read and forward a message-body on any request; if the
request method does not include defined semantics for an entity-body,
then the message-body SHOULD be ignored when handling the request.
I've already reviewed several related discussions on this topic on SO and beyond, such as:
Is an entity body allowed for an HTTP DELETE request?
Payloads of HTTP Request Methods
HTTP GET with request body
Most discussions seem to concur that providing a message body on a DELETE may be allowed, but is generally not recommended.
Further, I've noticed a trend in various HTTP client libraries where more and more enhancements seem to be getting logged for these libraries to support request bodies on DELETE. Most libraries seem to oblige, although occasionally with a little bit of initial resistance.
My use case calls for the addition of some required metadata on a DELETE (e.g. the "reason" for deletion, along with some other metadata required for deletion). I've considered the following options, none of which seem completely appropriate and inline with HTTP specs and/or REST best practices:
Message Body - The spec indicates that message bodies on DELETE have no semantic value; not fully supported by HTTP clients; not standard practice
Custom HTTP Headers - Requiring custom headers is generally against standard practices; using them is inconsistent with the rest of my API, none of which require custom headers; further, no good HTTP response available to indicate bad custom header values (probably a separate question altogether)
Standard HTTP Headers - No standard headers are appropriate
Query Parameters - Adding query params actually changes the Request-URI being deleted; against standard practices
POST Method - (e.g. POST /resourceToDelete { deletemetadata }) POST is not a semantic option for deleting; POST actually represents the opposite action desired (i.e. POST creates resource subordinates; but I need to delete the resource)
Multiple Methods - Splitting the DELETE request into two operations (e.g. PUT delete metadata, then DELETE) splits an atomic operation into two, potentially leaving an inconsistent state. The delete reason (and other related metadata) are not part of the resource representation itself.
My first preference would probably be to use the message body, second to custom HTTP headers; however, as indicated, there are some downsides to these approaches.
Are there any recommendations or best practices inline with REST/HTTP standards for including such required metadata on DELETE requests? Are there any other alternatives that I haven't considered?
Despite some recommendations not to use the message body for DELETE requests, this approach may be appropriate in certain use cases. This is the approach we ended up using after evaluating the other options mentioned in the question/answers, and after collaborating with consumers of the service.
While the use of the message body is not ideal, none of the other options were perfectly fitting either. The request body DELETE allowed us to easily and clearly add semantics around additional data/metadata that was needed to accompany the DELETE operation.
I'd still be open to other thoughts and discussions, but wanted to close the loop on this question. I appreciate everyone's thoughts and discussions on this topic!
Given the situation you have, I would take one of the following approaches:
Send a PUT or PATCH: I am deducing that the delete operation is virtual, by the nature of needing a delete reason. Therefore, I believe updating the record via a PUT/PATCH operation is a valid approach, even though it is not a DELETE operation per se.
Use the query parameters: The resource uri is not being changed. I actually think this is also a valid approach. The question you linked was talking about not allowing the delete if the query parameter was missing. In your case, I would just have a default reason if the reason is not specified in the query string. The resource will still be resource/:id. You can make it discoverable with Link headers on the resource for each reason (with a rel tag on each to identify the reason).
Use a separate endpoint per reason: Using a url like resource/:id/canceled. This does actually change the Request-URI and is definitely not RESTful. Again, link headers can make this discoverable.
Remember that REST is not law or dogma. Think of it more as guidance. So, when it makes sense to not follow the guidance for your problem domain, don't. Just make sure your API consumers are informed of the variance.
What you seem to want is one of two things, neither of which are a pure DELETE:
You have two operations, a PUT of the delete reason followed by a DELETE of the resource. Once deleted, the contents of the resource are no longer accessible to anyone. The 'reason' cannot contain a hyperlink to the deleted resource. Or,
You are trying to alter a resource from state=active to state=deleted by using the DELETE method. Resources with state=deleted are ignored by your main API but might still be readable to an admin or someone with database access. This is permitted - DELETE doesn't have to erase the backing data for a resource, only to remove the resource exposed at that URI.
Any operation which requires a message body on a DELETE request can be broken down into at it's most general, a POST to do all the necessary tasks with the message body, and a DELETE. I see no reason to break the semantics of HTTP.
I suggest you include the required metadata as part of the URI hierarchy itself. An example (Naive):
If you need to delete entries based on a date range, instead of passing the start date and end date in body or as query parameters, structure the URI such a way that you pass the required information as part of the URI.
e.g.
DELETE /entries/range/01012012/31122012 -- Delete all entries between 01 January 2012 to 31st December 2012
Hope this helps.
I would say that query parameters are part of the resource definition, thus you can use them to define the scope of your operation, then "apply" the operation.
My conclusion is that Query Parameters as you defined it is the best approach.
The other verbs all make sense to me, but I don't have much context for "post" as a verb. Is it like post as in Post Office (which makes some sense, although seems like a stretch) or post like post on a bulletin board (makes less sense to me)? Does anyone know who decided on "POST" and why it was selected?
Well, "post like post on a bulletin board" comes pretty close to the answer, I guess. In the end, that's exactly one of those functionalities this method was designed for. POST is always meant to post stuff to some kind of 'factory' to be handled by it - otherwise you could just use PUT. Let's have a look at RFC2616, Section 9.5:
The POST method is used to request that the origin server accept
the entity enclosed in the request as a new subordinate of the
resource identified by the Request-URI in the Request-Line. POST is
designed to allow a uniform method to cover the following
functions:
- Annotation of existing resources;
- Posting a message to a bulletin board, newsgroup, mailing list,
or similar group of articles;
- Providing a block of data, such as the result of submitting a
form, to a data-handling process;
- Extending a database through an append operation.
Of course this is not the exact definition of why it is called POST, but I think this might give some clues about the idea behind it.
Maybe we could also have a look at some meanings of the word 'post' (http://www.thefreedictionary.com/Post, the 3rd definition) - according to that, post as a verb can mean
To mail (a letter or package)
To inform of the latest news
To transfer (an item) to a ledger in bookkeeping
To make the necessary entries in (a ledger)
And this is exactly what POST does (metaphorically). If you want to send en email, you let your email-provider handle it and then inform you about the state. And this is also the difference between PUT and POST: If the client is in charge of handling the resource, you use PUT (because you know what to put and where to put it).
So, theoretically, if you knew the IP-address of the person you want to send the email to, you wouldn't need your provider to find this stuff out for you. But now, you know what to put, but not exactly where. So in this case, you use POST. You 'inform the server of the latest news' and the server decides where to put it. So you can think of it as 'transfering an item' to a resource that's already present (like a thread in a forum or something) - you just want to append something.
I hope this makes any sense...
The POST method is used to request that the origin server accept the entity enclosed in the request as a new subordinate of the resource identified by the Request-URI in the Request-Line. POST is designed to allow a uniform method to cover the following functions:
Annotation of existing resources;
Posting a message to a bulletin board, newsgroup, mailing list, or similar group of articles;
Providing a block of data, such as the result of submitting a form, to a data-handling process;
Extending a database through an append operation.
W3 / POST
REST asks developers to use HTTP methods explicitly and in a way that's consistent with the protocol definition. This basic REST design principle establishes a one-to-one mapping between create, read, update, and delete (CRUD) operations and HTTP methods. According to this mapping:
To create a resource on the server, use POST.
To retrieve a resource, use GET.
To change the state of a resource or to update it, use PUT.
To remove or delete a resource, use DELETE.
IBM / REST
When we are POSTing, we really are sending new data (creating resource) but not going to get it or calling about updates or asking for shredding our older documnets.
I don't think that post as in 'to post a letter' is much of a stretch. A POST request is a message containing data after all. As to the who, the verbs come from HTTP, so the origins would be the Html spec written by Tim Berners-Lee in 1995.
I have REST services which should receive really long queries via GET. Say for example I want to query a service with many geographical coordinates to find out something about all this coordinates.
1) My first thought was to use long URIs and increase the max URI length of the servlet container.
It would look like this:
GET http://some.test/myresource?query={really big JSON object}
But it seems that URIs longer than 2 KB are not reliable due to old proxy servers (is that right?).
2) My workaround is to create a temporary resource via POST first and use the URI of this resource as parameter in the actual GET request. That would look like this:
POST http://some.test/temp
Request Body: {really big JSON object}
201 Created Location: http://some.test/temp/12309871
GET http://some.test/myresource?query=http://some.test/temp/12309871
3) Use body of GET request. I've read the answers to the question whether it is a good idea to use the body of a GET request for the query, and the consensus is: no. Even Roy Fielding says that this is a bad idea.
4) Another approach could be to interpret POST as "create query result resource" and delete this resource after the request. But I consider that to be not RESTful and to be a bad idea.
Is there a better way to handle big queries with GET requests?
Use PUT.
Why? For the following reasons:
Just because the verb PUT 'may update' the resource, doesn't mean it will or must alter underlying state of the resource.
No new resource identifier (url) should be created by the API side of a PUT. Yes, technically a PUT with a client specified identifier is possible, but in this case you're hitting an existing resource.
PUT is like GET in the fact that it should be idempotent, meaning the results of the request will always be the same regardless of how often you call it and it has no side effects.
PUT means you're putting resource data to an existing resource. In terms of a article or post in the document / blog post worlds, it would be like uploading a new revision of some document to an existing resource URL. If you upload the same revision to the same URL, nothing should change in the resource you get back.
In your case, the geo data is some new resource data you're uploading and the result you get back should be the same every time you make the same request.
A more purist method to use the GET verb for the request might be:
Create an endpoint for a query resource type
POST the JSON set of query details to a query resource endpoint and get an identifier for the query resource (say it returns a query id of 123)
Submit to the get request a query identifier http://some.test/myresource?query_id=123
Delete the query resource 123
I see the pure method much more overhead than using PUT with query resource data in the body.
I thought that the whole point in REST was to work on "documents" (or something alike). The URI part of a request is there to identify uniquely the resource to work on. The body part in contrast is there for the "contents" part of the document.
Hence, use the "body" part of the request.
Also note that the semantics of a "GET" request isn't supposed to be used for "PUTTING" or "POSTING" documents (comment in relation to your "query" example above which seems to "create" an object).
In any case, as you have pointed out, the URI part is limited (for good reason I am sure).
If you are concerned with caching, then the use of ETag/Last-Modified fields (in conjunction with "conditional GET" helps for this purpose.
Here is a slight variation on your second option. Create yourself a processor resource called QueryMaker. POST your parameters to it and let it redirect you to a temporary query resource that will return your results.
POST /QueryMaker
Body: Big Json representation of parameters
303: See Other
Location: http://example.org/TemporaryQueries/123213
If you are using a GET request to send large objects, you are not using REST correctly.
GET should be used for retrieving
resources (via some sort of unique
identifier)
POST should be used for
creating resources (with the contents
in the body)
PUT should be used for
updating a resource (with the
contents in the body)
DELETE should be used for deleting a resource
If you follow these guidelines you will never have to have overly long URIs.
Some best practice REST guidelines are here: http://www.xml.com/pub/a/2004/08/11/rest.html
The biggest limitation of URL lengths on the open Web is actually IE, which constraints them to 2083 characters.
Some proxies (e.g., all but the most recent versions of Squid) will limit them to about 4k, although this is moving towards 8k slowly.
Your #2 workaround is a good approach, depending on your use case.
Sending bodies on GETs may be allowed by some implementations, and disallowed by others, so it's a bad idea for interoperability as well as theoretical reasons. Most importantly, how will a cache know what to use as a key?
Can't you just send the big JSON data with the GET request body, instead of creating the temp resource?
Although it's not 100% kosher, i've found it works nicely with firefox and IE and IMO, the querystring is inelegant and usually exposes implementation details that don't belong in the URI. Just make sure to add a cache buster querystring parameter if you need up-to-date data because the server will ignore the data when determining whether it can return a cached response.
See here for a discussion of pros and cons of stuffing data in the GET request body.
I have a resource that has a counter. For the sake of example, let's call the resource profile, and the counter is the number of views for that profile.
Per the REST wiki, PUT requests should be used for resource creation or modification, and should be idempotent. That combination is fine if I'm updating, say, the profile's name, because I can issue a PUT request which sets the name to something 1000 times and the result does not change.
For these standard PUT requests, I have browsers do something like:
PUT /profiles/123?property=value&property2=value2
For incrementing a counter, one calls the url like so:
PUT /profiles/123/?counter=views
Each call will result in the counter being incremented. Technically it's an update operation but it violates idempotency.
I'm looking for guidance/best practice. Are you just doing this as a POST?
I think the right answer is to use PATCH. I didn't see anyone else recommending it should be used to atomically increment a counter, but I believe RFC 2068 says it all very well:
The PATCH method is similar to PUT except that the entity contains a
list of differences between the original version of the resource
identified by the Request-URI and the desired content of the resource
after the PATCH action has been applied. The list of differences is
in a format defined by the media type of the entity (e.g.,
"application/diff") and MUST include sufficient information to allow
the server to recreate the changes necessary to convert the original
version of the resource to the desired version.
So, to update profile 123's view count, I would:
PATCH /profiles/123 HTTP/1.1
Host: www.example.com
Content-Type: application/x-counters
views + 1
Where the x-counters media type (which I just made up) is made of multiple lines of field operator scalar tuples. views = 500 or views - 1 or views + 3 are all valid syntactically (but may be forbidden semantically).
I can understand some frowning-upon making up yet another media type, but I humbly suggest it's more correct than the POST / PUT alternative. Making up a resource for a field, complete with its own URI and especially its own details (which I don't really keep, all I have is an integer) sounds wrong and cumbersome to me. What if I have 23 different counters to maintain?
An alternative might be to add another resource to the system to track the viewings of a profile. You might call it "Viewing".
To see all Viewings of a profile:
GET /profiles/123/viewings
To add a viewing to a profile:
POST /profiles/123/viewings #here, you'd submit the details using a custom media type in the request body.
To update an existing Viewing:
PUT /viewings/815 # submit revised attributes of the Viewing in the request body using the custom media type you created.
To drill down into the details of a viewing:
GET /viewings/815
To delete a Viewing:
DELETE /viewings/815
Also, because you're asking for best-practice, be sure your RESTful system is hypertext-driven.
For the most part, there's nothing wrong with using query parameters in URIs - just don't give your clients the idea that they can manipulate them.
Instead, create a media type that embodies the concepts the parameters are trying to model. Give this media type a concise, unambiguous, and descriptive name. Then document this media type. The real problem of exposing query parameters in REST is that the practice often leads out-of-band communication, and therefore increased coupling between client and server.
Then give your system a uniform interface. For example, adding a new resource is always a POST. Updating a resource is always a PUT. Deleting is DELETE, and getiing is GET.
The hardest part about REST is understanding how media types figure into system design (it's also the part that Fielding left out of his dissertation because he ran out of time). If you want a specific example of a hypertext-driven system that uses and doucuments media types, see the Sun Cloud API.
After evaluating the previous answers I decided PATCH was inappropriate and, for my purposes, fiddling around with Content-Type for a trivial task was a violation of the KISS principle. I only needed to increment n+1 so I just did this:
PUT /profiles/123$views
++
Where ++ is the message body and is interpreted by the controller as an instruction to increment the resource by one.
I chose $ to deliminate the field/property of the resource as it is a legal sub-delimiter and, for my purposes, seemed more intuitive than / which, in my opinion, has the vibe of traversability.
I think both approaches of Yanic and Rich are interresting. A PATCH does not need to be safe or indempotent but can be in order to be more robust against concurrency. Rich's solution is certainly easier to use in a "standard" REST API.
See RFC5789:
PATCH is neither safe nor idempotent as defined by [RFC2616], Section
9.1.
A PATCH request can be issued in such a way as to be idempotent,
which also helps prevent bad outcomes from collisions between two
PATCH requests on the same resource in a similar time frame.
Collisions from multiple PATCH requests may be more dangerous than
PUT collisions because some patch formats need to operate from a
known base-point or else they will corrupt the resource.