REST and HATEOS definitions self-violating? - rest

QUESTION: Can HATEOAS in REST be considered a valid proposition when it is self-evidently internally contradictory : If an interface is said to not be RESTful (according to Fielding), when a Client cannot utilize the in-band data (URI's) from the Response Hypertext (Hypermedia) without reference to an external (out-of-band) document, and therefore tightly coupling Client and Server according to Fielding, how can we do anything but fail Roy Fielding's prima facie assertion?
It seems to me that Fielding's exposition makes HATEOAS and REST an internally contradictory proposition that cannot be fulfilled with the current technology - unless someone knows how to it without referring to out-of-band data?
(EDIT) I suspect no-one is reading/has read Fielding's rant, so here's the most relevant piece:
"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.]"
We all keep asserting that we must have out-of-band knowledge of the URI's available methods beyond the initial data stream. Note how Fielding very stridently tells us that this is failure. Yet, it's how we're all dong it, me included. But Fielding screams No back at us.
(EDIT: because no-one's reading ithe explanation).

There are three pieces of prior knowledge that REST allows: the home page of the API (in browsers, this is supplied by the user typing into the address bar); an understanding of common media types, such as HTML (provided by browser developers); and link relations that inform a client application can look at when deciding what to do (e.g. rel=stylesheet links get automatically downloaded and parsed by graphical browsers to make the documents they render look pretty).
What REST prohibits is a client knowing it can do things like read an ID from a certain place on your webpage and then append it onto the end of youtube.com/watch?v= to get to a YouTube video. In stead, you should define a "video-clip" link relation and use your media type's hyperlinking mechanism to provide the full URL, not just the ID.

So, the answer to my question seems to be that none us know how to do it the way Fielding said it should be done, so none us know how to acheive a HATEOAS compliant RESTful API without violating Fielding's primary assertion regarding out-of-band data, and therefore making our app non-RESTful in so doing.
Everyone stridently believes they have this answer right, but we're all ignoring the fact that Roy Fielding says we are all wrong. He says we're all writing RPC's.
Roy Fielding: REST APIs must be hypertext-driven
"I am getting frustrated by the number of people calling any HTTP-based interface a REST API"
It boils down to the fact that we are not building the kind of apps that lend themselves to Roy's thesis on REST. Indeed, he believes the proposition that we would 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.
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 allow the Client to be written to be RESTful, but in so doing I am using the Response Body, which Fielding says is not what he intended.

No, REST and HATEOAS do not contradict each other. In fact the proposition doesn't even make sense because HATEOAS is part of the definition of REST. They aren't two separate things.
To better understand what Fielding means by out-of-band knowledge I suggest thinking about a web browser. A web browser is a generic client that implements a set of standards (HTTP, HTML, URI, etc). Any of the standards that the client implements can be thought of as in-band. Anything that is not expressed in one of the standards implemented by the generic client is out-of-band.
If you have a resource that looks like this
GET /some/resource HTTP/1.1
Content-Type: application/json
{
"author": "/authors/me",
"foo": 42
}
As a human, I can look at this and recognize that the value of "author" looks like a link and I can try to follow it, but a generic browser only recognizes it as plain JSON. It's just a string. Interpreting that "author" is a link requires out-of-band knowledge.
The solution is to choose a hypermedia media type that defines how to express a link. Here's that example expressed in HAL.
GET /some/resource HTTP/1.1
Content-Type: application/hal+json
{
"_links": {
"author": { "href": "/authors/me" }
},
"foo": 42
}
A generic client can be developed that understands HAL. My API and your API can both use the same client without knowing anything about each other or the client knowing about either API.
The question about how to know which method to use with a link is also up to the hypermedia media type to define. HTML does it by defining constructs whose semantics imply a method. The anchor tag foo implies a GET request. The form tag has similar well defined semantics. A JSON based hypermedia format will have to define it's own structures and semantics for those structures. All of this is considered in-band because it's part of a standard that can be implemented by a generic browser.
So, if you want to get the Roy Fielding stamp of approval for your REST API, you need to be using a standardized generic hypermedia media type that is capable of describing everything your application needs to do. My favorite is JSON Hyper-Schema. It's the best at describing something like a form post without out-of-band knowledge because it uses a JSON Schema to describe what data the server expects.

Related

how to design a RESTful api for redeem a coupon?

I am designing a RESTful api for coupon redemption.
Each coupon can be redeemed only once, after redemption the coupon is on longer valid.
(POST) /coupons/{couponCode}/redeem
seems violate the RESTful guidelines since redeem is a verb.
can I just change redeem to redemption?
or can I just use
(POST) /coupons/{couponCode}?
btw I am not quite sure why use POST instead of PATCH, is it because of PATCH is idempotent and POST is not? I mean, when the coupon is redeemed for the first time, it will be marked as redeemed in database, but once it's done, the same request won't update this value anymore.
seems violate the RESTful guidelines since redeem is a verb
REST doesn't care what spelling you use for your resource identifiers.
So all of these choices are fine
POST /coupons/{couponCode}/redeem
POST /coupons/{couponCode}
POST /{couponCode}/redeem
POST /i/am/a/banana
POST /4ccd2f6f-a81e-4b70-b45c-20ce9f8732b5
Identifier spelling conventions are like variable naming conventions; they exist only to ease the burden of people, and are subject to local convention. The machines don't care.
The thing that matters is that the target uri used for your change matches the identifier of the resource in the cache that you want to invalidate.
I am not quite sure why use POST instead of PATCH, is it because of PATCH is idempotent and POST is not?
No. The difference is that PATCH promises that the payload is a patch document, which is to say a representation of a set of edits to the representation of "the" resource, whereas POST just says "this is a message to be processed by the resource".
(Both POST and PATCH are not idempotent, as it happens.)
Imagine a document store, where the documents are about one terabyte in size. You might want to change one of those documents. The natural way to do it is to GET the current representation, make your changes, and then PUT your version of the document back. But if your change is very small, then there's a lot of wasted work carrying duplicated copies of the document around.
So instead, we use PATCH, so that we can instead copy a small representation of the edit, rather than the full document.
POST is more general -- it's an unsafe message with a body, and that's pretty much all it promises. That body might be a new representation of the resource, or a patch to be applied to the current representation, or something entirely different.
why use redeem doesn't violate REST? shouldn't be verbs only HTTP methods?
Because REST is an architectural style, and it says that resource identifiers should be URL (RFC 1738) -- although these days that is generally understood to mean URI (RFC 3986) -- or URN (RFC 8141).
If you look at RFC 3986, I think you will find that the word "verb" doesn't appear anywhere in the document. You can review the ABNF rules for interpreting URI, and there is nothing about verbs in there anywhere.
REST doesn't care -- the URI is, in its primary use case, just an opaque sequence of bytes that are used by the client.
For example, try clicking on this link in your browser, does it work?
https://www.dictionary.com/browse/stop
The fact that "stop" happens to be a verb in English doesn't interfere with its function.
I also see some RESTful design guidelines suggest not to use verbs
Yup, the web is full of advice from people who don't understand the subject, or who do understand the subject and don't articulate it clearly, and so on.
REST doesn't offer enforce any particular URI design style.
In REST, the identifier is just an identifier, like a UUID, a hash signature, or a surrogate key. Within the context of an HTTP message, it doesn't mean anything, it's just a cache key. The message semantics come from the method, not the request-target.
GET /A/post HTTP/1.1
POST /B/get HTTP/1.1
DELETE /C/put HTTP/1.1
PUT /D/patch HTTP/1.1
There's no ambiguity in these request lines, the first token is the method that defines the semantics, the second token is just an arbitrary identifier. The machines will get them right every single time.
Recommended Viewing
Jim Webber, 2011
Stefan Tilkov, 2014
It would be better for you to use a url route where you expose the redeem action. This route should use the POST http request because you will modify a resource on the server, and will take as parameter your couponCode.
(POST) /coupons/redeem/{couponCode}
I don't think there is a difference between redeem and redemption. I think a verb like redeem is better to designate an action.
http PATCH or PUT request can be used too. As a convention, we use PATCH or PUT to update a resource after it has been created to change one of its attributes. If you are willing to use PATCH request to update let's say a coupon that you already created, then you can define a url route without the redeem action. The request body would contain the fields to be updated for the coupon object (for example status from "pending" to "redeemed")
(PATCH / PUT) /coupons/{couponCode}
Many use the following convention:
GET /objects (return list of objects)
GET /objects/id (return object)
PUT /objects/id (update object)
POST /objects (add object)
DELETE /objects/id (remove object)

Handling write only resources in a HATEOAS based REST api

Let's assume I have a REST resource for my users. If the client requests one specific user with GET, the api returns the following json.
GET https://localhost:8080/api/user/xy
{
"name": "John Smith",
...
"_links": [{
"rel": "self",
"href": "https://localhost:8080/api/user/xy"
},
{
"rel": "changepassword",
"href": "https://localhost:8080/api/user/xy/password"
}]
}
As you can see the api provides a reference (in the _links section) to a resource where the client can change the password. I expect now the client to update the password when sending a PUT request to this reference.
Now my questions:
Is this a good/correct approach to implement a use-case like "change password" in a HATEOAS based REST api? Or is there another/better approach?
What should the server return after changing the password successfully? I would probably expect the status 204 and an empty body.
For sure I don't want to show the user his current password. Therefor my server will return a code 405, if the client is trying to GET the password resource. Is it generally valid to have a "write only" resource in a REST api?
... in a HATEOAS based REST api
First things first, one of the few constraint REST implies is that HATEOAS is already in place and therefore HTTP clients use links to progress its current state. A client not utilizing HATEOAS is not a REST client as well as an API not including links offering a clinet new state-possibilities is not a RESTful API!
Concerning your actual questions, it always depends on how you model certain things. You can use PUT to update the field and then return a 204 No Content response to indicate that this field has no readable content. According to the Spec
If the target
resource does have a current representation and that representation
is successfully modified in accordance with the state of the enclosed
representation, then the origin server MUST send either a 200 (OK) or
a 204 (No Content) response to indicate successful completion of the
request.
returning a 204 No Content status code is eligible.
An other approach could send the old password to the service in order for the service to first check the current password against the provided old one and only then update the password. This might prevent attacks which try to alter the passwords of other users in case you do not use an encrypted connection anyways. In order to achive this validation check however the client is not able to use a simple PUT operation anymore unless you make the old password part of the new state. Here POST is probably better suited as it leaves the semantics to the implementor of the API. This can go as far as to maintain a history of the last n passwords which the new password may not be any of the former ones.
HTTP offers the OPTIONS method a client can use to determine which operations are suitable for certain endpoints. Zac Stewart explained the usefulness of the OPTIONS method in regards to RESTful APIs in a blog post, and also points out the current shortcommings plenty of HTTP server have in regards to the usage of OPTIONS.
Most HTTP frameworks will return a 405 Method Not Allowed response code in cases an endpoint is invoked with an operation that has no implementation by default. At least in Java either in Spring MVC/Rest data or in JAX-RS methods offered at certain endpoints have to be annotated with interfaces that correspond to HTTP methods. Invoking an endpoint with an operation that has now equivalent annotated method will produce a 405 error response automatically, though this might be language and framework dependant.

REST creation without persisting

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.

Where in a HATEOAS architecture do you specify the HTTP verbs?

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}

HTTP POST with URL query parameters -- good idea or not?

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}/ ...
{
...
}