with the representation of the query as XML in the request body.
To match the rest of the RESTful API, a GET to the same URl would return the saved query itself, not the results of running the query.
So, what should the HTTP method and URL to actually execute the query and return the results look like?
Perhaps a GET to something like:
with parameter data in the query string?
Is there a best-practice approach?
This seems to be a standard pattern for more process oriented interactions where the "PUT" representation doesn't match the "GET" representation.
For our system, queries are being considered "first class" data model items. Clients will create named, persistent items that represents queries they'll want to repeatedly run with various parameterized values -- I guess you could think of them as persisted representations of prepared statements.
Clients will want to be able to create, delete, fetch, and modify the query definition ad nauseam.
For this I've set up the example URI:
where PUT is used to create/update the query, GET is used to fetch its representation, and DELETE to remove it from the data model (just like all the other persisted items in the data model).
So, what you are saying is that a POST to this URI, with the parameterized values, would create a temporary child resource that represents the result (returned via the Location header) which could then be fetched with a GET to that child resource.
Question: in such a scenario, would it be improper to return the results directly as the response to the POST? It's unlikely that the clients would store a child result URI for later or repeated use, so I'm not sure there's much utility in creating the temporary resource unless not doing so violates an expected or best-practice RESTful precept.
Can you comment on that?
Bear Bibeault wrote:
Question: in such a scenario, would it be improper to return the results directly as the response to the POST?
you should not return the result. The creation of the child resource is the parent's action and the result of the operation is the URI to the created resource.
By trying to return the result immediately you are giving up some wiggle room. Some queries and processes can take a long time to complete. The child URI may be available immediately but when accessed it may give you the "still working on it" representation. For cache-ability concerns a "good resource" doesn't change all that often. If you were to issue the query every time somebody GETs the URI the representation isn't cache-able.
Maybe your query result should include a lifetime property so that the server is free to delete it once its lifetime expires (for one-off queries). Or a "result expiry" property (leading to a Cache-Control HTTP Header enabling caching down the line) making sure that a GET will only refresh the result if the current "result has expired" (for re-usable queries).
Peer Reynders wrote:By trying to return the result immediately you are giving up some wiggle room. ... the representation isn't cache-able.
OK, I've got that. Though it's unlikely that cachability will be an issue as it is unlikely that a client will repeat the same query with the same parameters within a timeframe that we'd want to keep the result around for. Are there other benefits?
I'm imagining clients that hem-and-haw over having to do the subsequent GET rather than just receiving the results directly in the POST response.
Would it be deemed acceptable to have this a client-defined property: choose to receive direct results or a GET-able URI?
Some queries and processes can take a long time to complete.
This is a very good point. We haven't really designed the back-end query architecture yet, and I don;t think anyone is yet anticipating such asynchronous behavior, but it's something we did end up having to do at my previous job. I can see how the child-resource solution fits into that nicely.
Bear Bibeault wrote:Would it be deemed acceptable to have this a client-defined property: choose to receive direct results or a GET-able URI?
Given the uniform interface constraint of Resource-Oriented Architecture, POST is used by "factory resources" as the factory method. POST is the only non-idempotent method of the bunch, and creating child resources without a URI is a non-idempotent operation. Retrieving query results should be an idempotent operation (i.e. GET). (Sample Chapter 4 The Resource-Oriented Architecture)
RESTful Web Services: Chapter 8 REST and ROA Practices
Overloading POST (p.220) wrote: ...
This is how most web applications work. XML-RPC and SOAP/WSDL web services also run over overloaded POST. I strongly discourage the use of overloaded POST, because it ruins the uniform interface. If you're tempted to expose complex objects or processes through overloaded POST, try giving objects or processes their own URIs, and exposing them as resources. I show several examples of this in "Resource Design" later in this chapter.
There are two noncontroversial uses for overloaded POST. The first is to simulate HTTP's uniform interface for clients like web browsers that don't support PUT or DELETE. The second is to work around limits of the maximum length of a URI. The HTTP standard specifies no limit on how long a URI can get, but many clients and servers impose their own limits: Apache won't respond to requests for URI's longer than 8KB. If a client can't make a GET request to http://www.example.com/numbers/11111111 because of URI length restrictions (imagine a million more ones there if you like), it can make a POST request to http://www.example.com/numbers?_method=GET and put "11111111" in the entity body.
A rule of thumb: if you're using POST, and never expose GET and POST on the same URI, you're probably not exposing resources at all. You've got an RPC-style service.
The principles of REST and the ROA are not arbitrary restrictions. They're simplifying assumptions that give advantages to resource-oriented services over the competition. RESTful resource-oriented services are simpler, easier to use, more interoperable, and easier to consume than RPC-style services.
Now lets be clear here. The assumption is simply that the URI does not fit. Also remember the addressability issue. While http://www.example.com/documents/conference?Title=RESTful and http://www.example.com/documents/conference?FullText=SOAP+XML%2FRPC may be processed by the same "Jersey resource" at http://www.example.com/documents, the REST architecture views them as two distinct resources that you can link to. So this exception doesn't give license to now change your query format representation, it expects you to place the remainder of the URI (e.g. conference?FullText=SOAP+XML%2FRPC) into the request body. It is also expected that the "Jersey resource" at http://www.example.com/documents can respond to real GET requests for less voluminous queries, so that the overloaded POST is only used in exceptional cases.
Bear Bibeault wrote:I'm imagining clients that hem-and-haw over having to do the subsequent GET rather than just receiving the results directly in the POST response.
If I had to explain this to Java programmers I would point out that they probably have no problem in Java with the fact that the query results would be returned in a container object. After general agreement I would then point out that in fact the object itself isn't returned - what is returned is a reference to the container object. You still have to access the container object itself to get at the query result data.
So the factory resource is returning a reference (URI) and you access (GET) the container resource to get the goods (the representation).