views:

262

answers:

3

Let's say you had a /companies resource that allowed clients to lookup public companies and you wanted clients to be able to lookup companies by Ticker, Location, and Location and industry

Would you keep the same URL in the form:

  • GET /companies/msft
  • GET /companies/usa
  • GET /companies/usa&software

This doesn't seem right. Any ideas?

A: 

You could accept any of those, but then return a Location: header pointing to the canonical address (presumably GET /companies/msft).

John Hyland
The latter two queries would return multiple companies.
Marcus
A: 

You have only one company, but multiple ways of getting to it, so I'd probably define /companies/[unique-name], and then various things like /companies/byticker/msft and /companies/bylocation/usa etc.

ankon
That's not a very RESTful approach.
workmad3
@workmad3 If you are going use that phrase, you need to explain which REST constraint is being violated. We are seeing *WAY* too much of use of the phrase "that's not RESTful" without any substantiation.
Darrel Miller
It's not RESTful because resources should have unique names. If you have several queries that return "the same thing", then they should return the unique name of the resource that can then be fetched rather than the resource itself. Having a unique name is important for cache coherency in a REST architecture. One name, one cache policy, one "place" to get it, change it, etc.
Will Hartung
I understand, sorry for not being clear: the uniquely named thing should be exactly the resource, the other parts would be aliases as you pointed up above, and return permanent redirects to the unique name in case they really are unique, or to resource collections ('USA' is not just Microsoft).
ankon
@Will How do you feel about pretty much all the "REST" frameworks that allow you to do GET /MyResource.xml and GET /MyResource.json? Two URLs one resource.I'm not taking either side, I'm just saying...
Darrel Miller
@Darrel - Those suffer the same problem. The key concern here is that the XML and JSON are semantically identical, they ARE the same resource. The trick is that they have different representations. Many would argue that GET /resource.xml is the same as GET /resource with an Accept: application/xml header. The real game here, though, is ensuring that your caching is correct. Making sure that both resources have identical cache policies. For example, you may want to ensure that both the JSON and XML representations expire at the same time, etags change similarly, etc. Only 0 characters are left.
Will Hartung
@Will Seems like Roy thinks that /Resource.xml, /Resource.json and /Resource are three different resources. I guess that makes both of us right and wrong at the same time :-) http://tech.groups.yahoo.com/group/rest-discuss/message/13960
Darrel Miller
@Will: A resource and a representation are two different things. You can't have a resource without a unique name because the name identifies the resource. You can have two resources that return an identical representation and one that means the same thing outside of the definition of resource. See http://stackoverflow.com/questions/1711653/three-step-buyonline-the-restful-way#comment-1591240 which references Fielding's thesis.
MikeSchinkel
+7  A: 

How about?

GET /Companies?ticker=MSFT

GET /Companies?country=USA

GET /Companies?country=USA&industry=software

The important thing is to identify the resource. The resource is "a list of Companies". Its media type could be an Atom list, or just an HTML document using UL LI tags. The query parameters affect the contents of the list, but conceptually, it is still "a list of companies".

You could create a distinct resource such as

GET /Companies/USA

but do you really need to. Are you going to POST to /Companies/USA? Are you going to delete /Companies/USA? If your application does not require the ability to perform additional operations on these specific sets of companies then why bother modeling them as distinct resources?

As a side note to this discussion, I like to distinguish more clearly when I am accessing a resource which is a single entity versus a list. i.e.

GET /Companies/USA

GET /Company/MSFT

I realize this is not the way some of the popular web frameworks work, but I have found it a useful distinction.

Darrel Miller
We would want to perform operations at the company level. Ie: /companies/msft
Marcus
See my update. I find the url /Companies/msft misleading. Is it returning a list of companies that have the ticker msft? or is it returning a representation of the the company resource? That's just my preference anyway. Url naming is about as significant to REST as class naming is to object oriented programming.
Darrel Miller
Got it. I agree.
Marcus
Maybe a different question but how would you handle urls where the companies could have two different ids (ie msft and a numerical id)? Do you allow gets to both /company/msft and /company/12345 where both the requests return Microsoft's info?
Marcus
You shouldn't have a single resource with multiple names. If you want aliases, those aliases can send redirects to the actual resource. So, GET /company/msft returns a 301 "Redirect Permanently", and the URL of the actual resource.
Will Hartung
Why is multiple resource names bad?
Marcus
@Marcus I struggled with this same issue for quite a while. I eventually gave up trying to support direct access to a resource using an alternate key in an URL. Now, if I need to "find" a resource through a secondary key then I treat the operation like any other kind of search. GET /Companies?ticker=MSFT and then get the canonical URL '/Company/1234' from the entry in the returned list.The debate as to whether a resource can have multiple URLs continues to rage on and there seems to be one camp that says you should never do it and another that says it is ok under certain circumstances.
Darrel Miller
I think the main reason why people say two urls for the same resource is bad is because of caching. If you PUT to one of the URLs, how does the cache know to invalidate its copy of the response from the alternate URL.
Darrel Miller
@Darrel Miller: /Companies/msft returns "msft" the company. If you want companies with the ticker of "msft" (which in this use-case is only one, but whatever) use /Companies?ticker=msft as you even have above.
MikeSchinkel