I'm designing an API to go over HTTP and I am wondering if using the HTTP POST command, but with URL query parameters only and no request body, is a good way to go.
Considerations:
"Good Web design" requires non-idempotent actions to be sent via POST. This is a non-idempotent action.
It is easier to develop and debug this app when the request parameters are present in the URL.
The API is not intended for widespread use.
It seems like making a POST request with no body will take a bit more work, e.g. a Content-Length: 0 header must be explicitly added.
It also seems to me that a POST with no body is a bit counter to most developer's and HTTP frameworks' expectations.
Are there any more pitfalls or advantages to sending parameters on a POST request via the URL query rather than the request body?
Edit: The reason this is under consideration is that the operations are not idempotent and have side effects other than retrieval. See the HTTP spec:
In particular, the convention has been
established that the GET and HEAD
methods SHOULD NOT have the
significance of taking an action other
than retrieval. These methods ought to
be considered "safe". This allows user
agents to represent other methods,
such as POST, PUT and DELETE, in a
special way, so that the user is made
aware of the fact that a possibly
unsafe action is being requested.
...
Methods can also have the property of
"idempotence" in that (aside from
error or expiration issues) the
side-effects of N > 0 identical
requests is the same as for a single
request. The methods GET, HEAD, PUT
and DELETE share this property. Also,
the methods OPTIONS and TRACE SHOULD
NOT have side effects, and so are
inherently idempotent.
If your action is not idempotent, then you MUST use POST. If you don't, you're just asking for trouble down the line. GET, PUT and DELETE methods are required to be idempotent. Imagine what would happen in your application if the client was pre-fetching every possible GET request for your service – if this would cause side effects visible to the client, then something's wrong.
I agree that sending a POST with a query string but without a body seems odd, but I think it can be appropriate in some situations.
Think of the query part of a URL as a command to the resource to limit the scope of the current request. Typically, query strings are used to sort or filter a GET request (like ?page=1&sort=title) but I suppose it makes sense on a POST to also limit the scope (perhaps like ?action=delete&id=5).
Everyone is right: stick with POST for non-idempotent requests.
What about using both an URI query string and request content? Well it's valid HTTP (see note 1), so why not?!
It is also perfectly logical: URLs, including their query string part, are for locating resources. Whereas HTTP method verbs (POST - and its optional request content) are for specifying actions, or what to do with resources. Those should be orthogonal concerns. (But, they are not beautifully orthogonal concerns for the special case of ContentType=application/x-www-form-urlencoded, see note 2 below.)
Note 1: HTTP specification (1.1) does not state that query parameters and content are mutually exclusive for a HTTP server that accepts POST or PUT requests. So any server is free to accept both. I.e. if you write the server there's nothing to stop you choosing to accept both (except maybe an inflexible framework). Generally, the server can interpret query strings according to whatever rules it wants. It can even interpret them with conditional logic that refers to other headers like Content-Type too, which leads to Note 2:
Note 2: if a web browser is the primary way people are accessing your web application, and application/x-www-form-urlencoded is the Content-Type they are posting, then you should follow the rules for that Content-Type. And the rules for application/x-www-form-urlencoded are much more specific (and frankly, unusual): in this case you must interpret the URI as a set of parameters, and not a resource location. [This is the same point of usefulness Powerlord raised; that it may be hard to use web forms to POST content to your server. Just explained a little differently.]
Note 3: what are query strings originally for? RFC 3986 defines HTTP query strings as an URI part that works as a non-hierarchical way of locating a resource.
In case readers asking this question wish to ask what is good RESTful architecture: the RESTful architecture pattern doesn't require URI schemes to work a specific way. RESTful architecture concerns itself with other properties of the system, like cacheability of resources, the design of the resources themselves (their behavior, capabilities, and representations), and whether idempotence is satisfied. Or in other words, achieving a design which is highly compatible with HTTP protocol and its set of HTTP method verbs. :-) (In other words, RESTful architecture is not very presciptive with how the resources are located.)
Final note: sometimes query parameters get used for yet other things, which are neither locating resources nor encoding content. Ever seen a query parameter like 'PUT=true' or 'POST=true'? These are workarounds for browsers that don't allow you to use PUT and POST methods. While such parameters are seen as part of the URL query string (on the wire), I argue that they are not part of the URL's query in spirit.
You want reasons? Here's one:
A web form can't be used to send a request to a page that uses a mix of GET and POST. If you set the form's method to GET, all the parameters are in the query string. If you set the form's method to POST, all the parameters are in the request body.
Source: HTML 4.01 standard, section 17.13 Form Submission
From a programmatic standpoint, for the client it's packaging up parameters and appending them onto the url and conducting a POST vs. a GET. On the server-side, it's evaluating inbound parameters from the querystring instead of the posted bytes. Basically, it's a wash.
Where there could be advantages/disadvantages might be in how specific client platforms work with POST and GET routines in their networking stack, as well as how the web server deals with those requests. Depending on your implementation, one approach may be more efficient than the other. Knowing that would guide your decision here.
Nonetheless, from a programmer's perspective, I prefer allowing either a POST with all parameters in the body, or a GET with all params on the url, and explicitly ignoring url parameters with any POST request. It avoids confusion.
I would think it could still be quite RESTful to have query arguments that identify the resource on the URL while keeping the content payload confined to the POST body. This would seem to separate the considerations of "What am I sending?" versus "Who am I sending it to?".
The REST camp have some guiding principles that we can use to standardize the way we use HTTP verbs. This is helpful when building RESTful API's as you are doing.
In a nutshell:
GET should be Read Only i.e. have no effect on server state.
POST is used to create a resource on the server.
PUT is used to update or create a resource.
DELETE is used to delete a resource.
In other words, if your API action changes the server state, REST advises us to use POST/PUT/DELETE, but not GET.
User agents usually understand that doing multiple POSTs is bad and will warn against it, because the intent of POST is to alter server state (eg. pay for goods at checkout), and you probably don't want to do that twice!
Compare to a GET which you can do as often as you like (idempotent).
I find it perfectly acceptable to use query parameters on a POST end-point if they refer to an already-existing resource that must be updated through the POST end-point (not created).
For example:
POST /user_settings?user_id=4
{
"use_safe_mode": 1
}
The POST above has a query parameter referring to an existing resource, mirroring the GET end-point definition to get the same resource.
The body parameter defines how to update the existing resource.
Edited:
I prefer this to having the path of the end-point to point directly to the already-existing recourse, like some suggest to do, like so:
POST /user_settings/4
{
...
}
The reason is three-fold:
I find it has better readability, since the query parameters are named, like "user_id" in the above, in stead of just "4".
Usually, there is also a GET endpoint to get the same resource. In that case the path of the end-point and the query parameters will be the same and I like that symmetry.
I find the nesting can become cumbersome and difficult to read in case multiple parameters are needed to define the already-existing resource:
POST /user_settings/{user_id}/{which_settings_id}/{xyz}/{abc}/ ...
{
...
}
Related
I have a REST endpoint GET /api/rules. It takes several query parameters for filtering/querying, like type, name, owner, description, and tag. So you could end up with a URI like this:
GET /api/rules?name=rule1,rule2&owner=john,jane&description=VeryLongDescription
Specifically, I'm concerned that the description queried for could be very long and make the URI too long (I forget the limit). Should I create a POST version of this same endpoint for users that get a 414 URI Too Long response from the server?
I mean, generally speaking, when does it make sense to just make a POST that gets a resource? Anytime you introduce query params?
In theory URIs have no limits, but in practice they might be limited by implementations. If you have to circumvent limitations imposed by the implementation that are not inherent to the protocol, you should try to decouple them from your application.
If you're a purist, the more or less standard way of supporting functionality through the POST method is using the x-http-method-override header, which can be decoupled from your application if it's implemented as a request pre-processor. You can have the preprocessor convert the POST request to the GET request your application expects, converting the payload to a query string.
Here's an example of this approach in the Google Translate API: https://cloud.google.com/translate/v2/using_rest#Translate
If you're not a purist, or if that's too complicated for your users, or you don't want to use a custom header, I think it's fine to make a POST endpoint that gets a resource, as long as it's properly documented and the resource being queried is identified by the URI.
I am developing a restful web service based on a database query and the tool that i am using tends to generate the parameters as a part of the HTTP Header ?
I always thought the parameters for POST to the restful service should always be passed in HTTP Body ?
Any ideas what should be the best practice or the usual practice ?
For POST requests, you can do either, but generally you'll use the body of the request for content that you are appending, mutating, deleting, etc. or for any data that is simply too large to put in the URI while one generally uses URI parameters for information that identifies the resource that is being accessed or modified (such as the element's ID) or restrictions or other search criteria (e.g. page, limit, etc.).
The primary tradeoffs off the top of my head are linkability (do you need a special POST extension, for example, just for developers to test a particular handler on your server?), URI size limits, and also whether the user would need to perform a click in order to cause the request to be sent (though using POST body is not a substitute for requiring a valid XSRF token/signature on the request).
Did I miss any other tradeoffs?
Right now I have a REST service which creates a report via a POST:
POST http://myhost/reports
The report however is not persisted, and cannot later on be retrieved via a GET:
GET http://myhost/reports/{id}
Instead I return the report immediately in the response to the POST. Am I violating any REST principle here, e.g. anything a POST creates should always be accessible via a GET, or is this setup OK?
The POST method isn't a synonym to the create in CRUD. The POST method is used for any operation that isn't standardized, so as long as you document what it does, you're not violating REST, no matter what you do.
There's no such REST principle saying "anything a POST creates should always be accessible via a GET". This is a common misunderstanding due to conflating REST with CRUD. Read this answer for some clarification on that.
In informal language, what a POST says to the server is "take this data and apply it to the resource identified by the given URI, following the rules you documented for the resource media type."
No, you are not violating REST. As long as your interface is uniform it is up to you to determine what actions the urls of your API perform.
As part of your documentation you simply need to state which methods are valid for certain resources and which aren't. I really like to use the Twitter API as a good example of "What to do"
Example: Twitter REST API
POST statuses/update
does not create an object available for access at
GET statuses/update/3
The action performed by the POST method might not result in a resource
that can be identified by a URI. In this case, either 200 (OK) or 204
(No Content) is the appropriate response status, depending on whether
or not the response includes an entity that describes the result.
So according to the HTTP standard this is okay.
I was reading an article on HATEOAS and while I understand the idea of providing the URLs for further actions in the response, I don't see where you specify what HTTP verbs should usedto interact with those URLs.
For example, from What is HATEOAS and why is it important for my REST API?, how from this response
GET /account/12345 HTTP/1.1
HTTP/1.1 200 OK
<?xml version="1.0"?>
<account>
<account_number>12345</account_number>
<balance currency="usd">100.00</balance>
<link rel="deposit" href="/account/12345/deposit" />
<link rel="withdraw" href="/account/12345/withdraw" />
<link rel="transfer" href="/account/12345/transfer" />
<link rel="close" href="/account/12345/close" />
</account
do you know if I should issue an HTTP PUT or POST to /account/12345/close?
Don't puts verbs in your URIs (eg /account/12345/transfer). URIs represent resources, not actions.
The verbs to use are defined by the HTTP protocol (eg GET, POST, PUT, OPTIONS, DELETE etc). REST is a architecture design with a set of constraints, and HTTP is a protocol that adheres to these constraints. HTTP defines a limited set of verbs to transfer the state of a resource from client to server and vice versa. By definition you are constrained to these verbs only.
The client should decide what HTTP verb to use based on what it is trying to do. The server doesn't need to tell it what verbs there are, it already knows based on the HTTP protocol.
If the client needs to know what verbs it can use on a resource it can query the resource using the OPTIONS verb and look at Allow header in the response (assuming the server returns this information, which it should if it is being helpful). Some resources might only accept GET, while others may accept others such as POST and PUT.
Have a look at the HTTP specification to see what verb to use in what context.
To give an example from your original post. Say you have an account resource with a URI at
/accounts/12345
and you want to close the account. Remember REST is state transfer. The client is closing the account so it has the account in a state of closed on its end. It then transfers that state to the server so that the client and server both are in line with each other. So you PUT the clients state (which is the resource in a closed state) onto the server
PUT /accounts/12345
The body of the request should contain a representation of the resource in a closed state. Assuming you are using XML to represent the account resource it would be something like this
PUT /accounts/12345
<?xml version="1.0"?>
<account>
<account_number>12345</account_number>
<balance currency="usd">100.00</balance>
<state>closed</state>
</account>
The resource on the server now mirrors the resource on the client. Both are in a closed state. If you don't want to transfer the whole resource every time you make a change to one of its attributes you could split them out into a resource hierarchy. Make the status of the account its own resource and PUT to that to change it
PUT /accounts/12345/status
<?xml version="1.0"?>
<state>closed</state>
Your question has a lot of answers on Stackoverlow, but most of them skirt the reason you are asking, and I suspect you always find them partially disatisfying.
If we take Roy Fielding at his word, it is impossible to write most commercial interactive Client-apps as SOA RESTful/HATEOAS using HTTP/HTML. It might be possible in other mediums, I can't say.
So the practical answer is "look it up in the documentation" and "write your Client with that app-knowledge in it" with a side-helping of "ignore the fact that we're breaking Fielding's rules by doing that".
I tend to design JSON responses that provide this approach:
GET /account/12345 HTTP/1.1
{
"account": {
"number": "12345",
"currency": "usd",
"balance": "100.00",
"deposit": {
"href": "/account/12345/deposit",
"action": "POST"
},
"withdraw": {
"href": "/account/12345/withdraw",
"action": "POST"
},
"transfer": {
"href": "/account/12345/transfer",
"action": "POST"
},
"close": {
"href": "/account/12345/close",
"action": "DELETE"
}
}
}
... adding additional properties to the design as needed, but these are the basics.
I believe this allows the consuming Client(s) to be written in a RESTful way, but in so doing I am using the Response Body, which Fielding says is not what he intended.
I'd offer this explanation seperate to the answer though:
Fielding says "I am getting frustrated by the number of people calling any HTTP-based interface a REST API." (http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven).
Note how he so stridently says "any" HTTP-based interface.
The most relevant segment in his 'lecture' is this:
"A REST API should be entered with no prior knowledge beyond the initial URI (bookmark) and set of standardized media types that are appropriate for the intended audience (i.e., expected to be understood by any client that might use the API). From that point on, all application state transitions must be driven by client selection of server-provided choices that are present in the received representations or implied by the user’s manipulation of those representations. The transitions may be determined (or limited by) the client’s knowledge of media types and resource communication mechanisms, both of which may be improved on-the-fly (e.g., code-on-demand). [Failure here implies that out-of-band information is driving interaction instead of hypertext.]"
He says this because an HTTP/HTML app URI media-type is just "text/html", and where is the Verb in that? There isn't one. A URI cannot tell you what Verb something requires for use/navigation, ergo you cannot use just the in-band data alone to construct the 'next' navigation dynamically in your Client.
He explained that he believes we render our URI's as part of CDATA that includes the "method" or that the context of the URI would self-evidently provide it, like the FORM element does. He explicitly rails against the OpenSocialst REST API stating that it is not RESTful.
Here: “anchor elements with an href attribute create a hypertext link that, when selected, invokes a retrieval request (GET) on the URI corresponding to the CDATA-encoded href attribute.” Identifiers, methods, and media types are orthogonal concerns — methods are not given meaning by the media type. Instead, the media type tells the client either what method to use (e.g., anchor implies GET) or how to determine the method to use (e.g., form element says to look in method attribute). The client should already know what the methods mean (they are universal) and how to dereference a URI.
Note that he says the Client should already know what the methods mean, he does not say that the Client should already know what they are - which is why you asked your question. A lot of people struggle with this, because we don't in fact build our apps like this in most SOA environments.
Like a lot of engineers, I just wish Fielding would come out with a clarification or re-statement, but not only has he not done so, he has published two further admonishments to us as engineers, doubling-down on his statement, saying that we should stop calling our API's RESTful and accept that we're building RPC's.
I think the JSON elements-like approach is a reasoble bridge, but I have no answer to the fact that we're using the Request Body to do it, not relying on the Media Type to imply it.
Finally, there is a newer Verb in HTTP called OPTIONS which, for a given URI, would return the allowed Verb actions list. I think Fielding had a hand in writing this HTTP revision. That would allow a Client to generically construct URI navigations without the forbidden internal app knowledge. But that has three issues I can think of in the practical world:
You would have to code a mechanism into your Service Aggregation to make that call for every URI you try to return, and since much data contains many URI's (_links in HAL) that adds a lot of extra 'hops' into your Service Response construction. We'd probably all complain about that.
Virtually no SOA site claiming to be RESTful actually implements an OPTIONS verb-method-call for you to do this enquiry with anyway.
We would all complain about the 'unecessary' extra calls it adds (especially in the eCommerce world) to a Client's processing and its tendency to push us beyond SLA requirements.
do you know if you should PUT or POST to /account/12345/close?
You consult the documentation for the API, that's how you know. HATEOS is not a replacement for formal documentation. Documentation is necessary for REST APIs just like any other API.
HATEOS lets you know what your other options are from a specific resource. It doesn't tell you why you would use those options, or what information you would send them. Content Types only express syntax and high level semantics, not application level semantics, so they're not documentation either.
If you want to know how to use a REST API, read the documentation. If you want someone else to use your REST API, provide them with documentation.
There's no magic here.
#Cormac Mulhall's answer is very good, but I'd like to suggest a refinement that I heard from a colleague:
Actions or events that happen to a resource can be treated as subordinate domain nouns, using the gerund form of the action verb or the event name, but should be placed under a meaningful path identifier such as "actions" or "events" or something similar. The resource representation that will be returned expresses state data about the action, so that POST or PUT operates as a request.
Suppose that orders have several lifecycle states. At some point after being drafted, an order is placed, fulfilled, or cancelled.
Information about these order actions would be located by putting the action name in plural noun form under the resource path with /actions to return details if the actions state is active, or 404 NOT FOUND otherwise.
https://order.api.foobar.com/v1.0/orders/{orderId}/actions/placements
https://order.api.foobar.com/v1.0/orders/{orderId}/actions/fulfillments
https://order.api.foobar.com/v1.0/orders/{orderId}/actions/cancellations
When these actions are idempotent (an order cannot be placed twice in a row), so these actions can be requested by PUT’ing of the appropriate representation to these URIs. When they are not idempotent, the are created by POST’ing to the plural form.
For example, to track approvals order, we could POST to:
https://order.api.foobar.com/v1.0/orders/{orderId}/approvals
and then we see information about individual approvals by doing a GET against:
https://order.api.foobar.com/v1.0/orders/{orderId}/approval/1
It is often useful to use an aggregate called something like "actions" to find all actions:
https://order.api.foobar.com/v1.0/orders/{orderId}/actions
We could POST to this, letting the representation declare what type of action is meant.
You can also get a list of actions across individual orders by leaving the {orderId} parameter off:
https://order.api.foobar.com/v1.0/orders/actions/placements
https://order.api.foobar.com/v1.0/orders/actions
These can be searched by adding query parameters:
https://order.api.foobar.com/v1.0/orders/actions/placements?since={sinceTimestamp}
Just wanted to get feedback on how I am planning to architect my API. Dummy methods below. Here's the structure:
GET http://api.domain.com/1/users/ <-- returns a list of users
POST http://api.domain.com/1/users/add.xml <-- adds user
POST http://api.domain.com/1/users/update.xml <-- updates user
DELETE (or POST?) http://api.domain.com/1/users/delete.xml <-- deletes user
Questions:
Is it OK to use just GET and POST?
Is it a good idea that I plan to rely on the filename to indicate what operation to do (e.g. add.xml to add)? Would it be better to do something like this: POST http://api.domain.com/1/users/add/data.xml?
What's a good way to keep these resources versioned? In my example, I use a /1/ after domain name to indicate version 1. Alternatives would be: http://api1.domain.com... or http://api-1.domain.com... or http://apiv1.domain.com... or http://api-v1.domain.com... or http://api.domain.com/v1/... or
What's the best way to authenticate?
Before you dig into REST, here are some terms you really need to grasp:
Resource - The things/data you want to make available in your API (in your case a "User")
URI - A universally unique ID for a resource. Should mention nothing about the method being performed (e.g. shouldn't contain "add" or "delete"). The structure of your URI however doesn't make your app any more or less RESTful - this is a common misconception.
Uniform Interface - A fixed set of operations you can perform on your resources, in most cases this is HTTP. There are clear definitions for the purpose of each of these HTTP methods.
The most unrestful thing about your URIs as they are right now is that they have information about the operation being performed right in them. URIs are IDs and nothing more!
Let's take a real world example. My name is Nathan. "Nathan" could be considered my ID (or in restful terms URI – for the purpose of this example assume I'm the only "Nathan"). My name/ID doesn't changed based on how you would like to interact with me, e.g. My name wouldn't change to "NathanSayHello" when you wanted to greet me.
It's the same for REST. Your user identified by http://api.domain.com/users/1 doesn't change to http://api.domain.com/users/1/update.xml when you want to update that user. The fact that you want to update that user is implied by the method you're using (e.g. PUT).
Here is my suggestion for your URIs
# Retrieve info about a user
GET http://api.domain.com/user/<id>
# Retrieve set all users
GET http://api.domain.com/users
# Update the user IDed by api.domain.com/user/<id>
PUT http://api.domain.com/user/<id>
# Create a new user. The details (even <id>) are based as the body of the request
POST http://api.domain.com/users
# Delete the user ID'd by api.domain.com/user/<id>
DELETE http://api.domain.com/user/<id>
As for your questions:
Use PUT and DELETE when appropriate and avoid overloading POST to handle these functions as it breaks HTTP's definition of POST. HTTP is your uniform interface. It is your contract with the API user about how they can expect to interact with your service. If you break HTTP, you break this contract.
Remove "add" altogether. Use HTTP's Content-Type header for specifying the mime-type of posted data.
Are you referring to the version of your API or the version of the resource? ETag and other response headers can be used to version the resources.
Many options here. Basic HTTP Auth (easy but insecure), Digest Auth, custom auth like AWS. OAuth is also a possibility. If security is of main importance, I use client side SSL certs.
1) On your design probably not. POST is not idempotent! So you should not use for the update or the delete, instead use PUT and DELETE from Rest
2) A better choice is to use the header Content-Type on the WS call, like: application/xml
3) Also on the header Content-Type u can use it: application-v1.0/xml
4) Not sure if it is the best, but probably the easiest way is to use HTTP's built-in authentication mechanisms in RFC 2617. An example: AWS Authentication
In REST, the HTTP "verb" is used to denote the operation type: you won't be able to express all the CRUD operations with only "GET" and "POST"
no: the URL of the resource is usually where the "document identifier" should appear
The version of the "document" can be transmitted in an HTTP response header upon creation/modification of the said resource. It should be the duty of the server to uniquely identify the resources - trying to do this on the client side will prove a daunting challenge i.e. keeping consistency.
Of course, there are many variations on the topic...
I did authentication based on headers. Something like
X-Username:happy-hamster
X-Password:notmyactualpassword
If you're concerned about security - do it through SSL.
Other implementations exist, of course. For instance, Amazon with their S3:
http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTAuthentication.html
If you don't have ability to make PUT and DELETE requests, it's considered a good practice to tunnel them through POST. In this case the action is specified in URL. If I recall correctly, RoR does exactly this:
POST http://example.com/foos/2.xml/delete
or
POST http://example.com/foos/3.xml/put
...
<foo>
<bar>newbar</bar>
</foo>
It's a bit offtop, but in regards to versioning and REST overall you might want to take a look at CouchDB. Here is a good book available on-line
Using post for create and delete functionality is not a good rest api design strategy. Use Put to create, post to update and delete to delete the resources.
For more information on designing rest apis follow the link - best practices to design rest apis