How can I use HATEOAS and Query Parameters for RESTful search?
I would like to design a RESTful search URI using query parameters. For example, this URI returns a list of all users:
GET /users
And the first 25 users with the last name "Harvey":
GET /users?surname=Harvey&maxRe开发者_如何学Pythonsults=25
How can I use hypermedia to describe what query parameters are allowed by the "/users" resource? I noticed that the new Google Tasks API just documents all the query parameters in the reference guide. I will document the list, but I would like to do it with HATEOAS too.
Thank you in advance!
Using the syntax described in the current draft of the URI template spec you would do:
/users{?surname,maxresults}
The other option is to use an html form:
<form method="get" action="/users">
<label for="surname">Surname: </label>
<input type="text" name="surname"/>
<label for="maxresults">Max Results: </label>
<input type="text" name="maxresults" value="25"/> <!-- default is 25 -->
<input type="submit" name="submitbutton" value="submit"/>
</form>
A form like this fully documents the available options and any defaults, it creates the specified URL and can be annotated with any further documentation that you care to put there.
I am no REST expert, but let me throw in my 2¢:
On the human Web, HTML forms are often used to build a URI to a representation of the search results. Problem is, the programmable Web does not have forms. But you could easily define something something analogous yourself, that is:
Define a media type for search descriptions, let's say
application/prs.example.searchdescription+json
(but take note of the P.S. at the end of this answer);Expose a sub-resource that represents a search for users,
/users/search
.
The second step would be achieved by linking to that sub-resource from somewhere else. For instance, let's say the client has requested GET /users
. It might receive something like this:
{ _links: [ …, { rel: "search", href: "/users/search" }, …] }
The client could follow that link and POST
a search specification to that resource URI, for example:
POST /users/search
…
Content-Type: application/prs.example.search-definition+json
…
{ criteria: { surname: "Harvey" }, maxResults: 25 }
Here, criteria
contains a (partial) representation of the objects to be found. This could be made into an arbitrarily complex description.
To a request as described above, the server might then reply with status code 200 OK
and, in the entity body, a link to a resource representing the results for the posted search:
{ _links: [ { rel: "results", href: "/users?surname=Harvey&maxResults=25" } ] }
The client can then navigate to the URI with the results
relation to get the search results, without ever having had to assemble an URI itself.
P.S.: When I originally wrote this, I had not yet realized that defining new media types all the time can become problematic. Mark Nottingham blogged about "media type proliferation" and how to combat it by making use of the
profile
link relation.
精彩评论