I'm looking for a reasonable way to represent searches as a RESTful URLs.
The setup: I have two models, Cars and Garages, where Cars can be in Garages. So my urls look like:
/car/xxxx xxx == car id returns car with given id /garage/yyy yyy = garage id returns garage with given id
A Car can exist on its own (hence the /car), or it can exist in a garage. What's the right way to represent, say, all the cars in a given garage? Something like:
/garage/yyy/cars ?
How about the union of cars in garage yyy and zzz?
What's the right way to represent a search for cars with certain attributes? Say: show me all blue sedans with 4 doors :
/car/search?color=blue&type=sedan&doors=4
or should it be /cars instead?
The use of "search" seems inappropriate there - what's a better way / term? Should it just be:
/cars/?color=blue&type=sedan&doors=4
Should the search parameters be part of the PATHINFO or QUERYSTRING?
In short, I'm looking for guidance for cross-model REST url design, and for search.
[Update] I like Justin's answer, but he doesn't cover the multi-field search case:
/cars/color:blue/type:sedan/doors:4
or something like that. How do we go from
/cars/color/blue
to the multiple field case?
Under REST principles, a URL identifies a resource. The following URL design patterns are considered REST best practices: URLs should include nouns, not verbs. Use plural nouns only for consistency (no singular nouns).
GET requests should be used to retrieve data when designing REST APIs; POST requests should be used to create data when designing REST APIs. Creating something is a side effect — if not the point. The HTTP GET method isn't supposed to have side effects. It's considered read-only for retrieving data.
For the searching, use querystrings. This is perfectly RESTful:
/cars?color=blue&type=sedan&doors=4
An advantage to regular querystrings is that they are standard and widely understood and that they can be generated from form-get.
The RESTful pretty URL design is about displaying a resource based on a structure (directory-like structure, date: articles/2005/5/13, object and it's attributes,..), the slash /
indicates hierarchical structure, use the -id
instead.
#Hierarchical structure# I would personaly prefer:
/garage-id/cars/car-id /cars/car-id #for cars not in garages
If a user removes the /car-id
part, it brings the cars
preview - intuitive. User exactly knows where in the tree he is, what is he looking at. He knows from the first look, that garages and cars are in relation. /car-id
also denotes that it belongs together unlike /car/id
.
#Searching# The searchquery is OK as it is, there is only your preference, what should be taken into account. The funny part comes when joining searches (see below).
/cars?color=blue;type=sedan #most prefered by me /cars;color-blue+doors-4+type-sedan #looks good when using car-id /cars?color=blue&doors=4&type=sedan #I don't recommend using &*
Or basically anything what isn't a slash as explained above.
The formula: /cars[?;]color[=-:]blue[,;+&]
, * though I wouldn't use the &
sign as it is unrecognizable from the text at first glance.
** Did you know that passing JSON object in URI is RESTful? **
Lists of options
/cars?color=black,blue,red;doors=3,5;type=sedan #most prefered by me /cars?color:black:blue:red;doors:3:5;type:sedan /cars?color(black,blue,red);doors(3,5);type(sedan) #does not look bad at all /cars?color:(black,blue,red);doors:(3,5);type:sedan #little difference
##possible features?## Negate search strings (!)
To search any cars, but not black and red:?color=!black,!red
color:(!black,!red)
Joined searches
Search red or blue or black cars with 3 doors in garages id 1..20 or 101..103 or 999 but not 5 /garage[id=1-20,101-103,999,!5]/cars[color=red,blue,black;doors=3]
You can then construct more complex search queries. (Look at CSS3 attribute matching for the idea of matching substrings. E.g. searching users containing "bar" user*=bar
.)
#Conclusion# Anyway, this might be the most important part for you, because you can do it however you like after all, just keep in mind that RESTful URI represents a structure which is easily understood e.g. directory-like /directory/file
, /collection/node/item
, dates /articles/{year}/{month}/{day}
.. And when you omit any of last segments, you immediately know what you get.
So.., all these characters are allowed unencoded:
a-zA-Z0-9_.-~
$-_.+!*'(),
;/?:@=&
<>"#%{}|^~[]`
Also see RFC 1738#page-20 for more character classes.
RFC 3986 see 2.2
Despite of what I previously said, here is a common distinction of delimeters, meaning that some "are" more important than others.
:/?#[]@
!$&'()*+,;=
More reading:
Hierarchy: see 2.3, see 1.2.3
url path parameter syntax
CSS3 attribute matching
IBM: RESTful Web services - The basics
Note: RFC 1738 was updated by RFC 3986
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With