Consider a simple photo storage service as an API. Users can only interact with the API if they’ve got an account. Let’s say authorization happens over HTTP Basic.
Given that, would you use URIs like /photos and /photos/{id} (as a photo list and photo detail resource, respectively)? What’s weird about those URIs is that my /photos is a different list of photos than your /photos — in other words, the resource represented depends on the information in the Authorization header.
It seems like URIs like /people/{my-uid}/photos and /people/{my-uid}/photos/{photo-id} are more “pure.” But now that’s weird because only one single user ever has access to a given URI (e.g only user #7 gets to access the entire space under /people/7). And the information in the URI is redundant with the information in the Authorization header.
I guess the question comes down to whether HTTP headers “should” be allowed to determine the resource returned.
So which would you use? Why?
Comments:
My gut reaction is that it doesn't matter as long as what ever option you choose, you use consistently throughout the API.
If you will never have API calls that don't require authorization, then your probably safe to have the results be specific to the authorized user. On the other hand, if you will have parts of the API which don't require auth, you probably should use the more verbose URIs to be consistent across the entire API.
You're implying more than just authorization required to access the API: You're implying that if you're authenticated you still can only access *your* /photos. Is that intentional? Did I miss something? Are you talking only about the PUT/POST URLs here?
I think in that case I'd prefer the more explicit/specific URL /photos/{id}. I don't think it causes confusion, the data required for that should be readily available and easy to put there, and some day when you decide some admin account should be able to access multiple users' /photos, you're already pretty much there.
Perhaps it's better to consider it from the other side, how would I as a user send someone the link? You know users will utilize the URL in an unexpected fashion, is it better to have (leak?) information in the URL?
Assuming your users are not sharing anything then {your}/photos being different to {my}/photos is no longer a problem - users only see their own data, the api is responding to an authenticated request correctly.
However, once you start sharing areas the rules change; /people/{id}/photos makes logical sense.
Shortcut routes; ie /myphotos would probably be more logical and memorable for users.
Each resource should have its own unique address on the web, whether or not it is available to the user requesting it. Otherwise there is no way for me to direct you to a photo of mine (that I have presumably made public or explicitly granted you access); you would go to example.com/photos/123 and see one of your own photos or a 404.
Brian: yes, the idea is that (a) you must be authenticated and (b) you can only see your own photos. So I'd say POST /photos/ (or maybe POST /users/{me}/photos) to store a photo and use GET to get 'em back.
And yes, I'm assuming that there's no sharing or anything going on - it's a private bucket.
I think its an excellent question to ask. I certainly would default (without thinking) to AUTH/session + /photos => my photos. And then torture myself with the API for global photo stream etc.
My gut reaction is to say /users/:user_id/photos for both with/without auth use cases.
Instead, I think I will revisit this page over the next few hours + days and see what interesting thoughts everyone has on the broad topic.
Assuming that each photo's id is unique, then I think the former (/photos/{id}) is the correct representation.
Each photo is a unique resource. Whether I am permitted access to that resource is a matter of authentication, and is orthogonal to the resourceish nature of the photo.
One of REST's central mandates is that we should use the full vocabulary of HTTP. That vocabulary includes the concepts of authentication (explicitly outside the URI) and a status code (403) denoting that there's a resource to be had at the URI you requested, but you're not allowed to have it. Why would HTTP supply this vocabulary if not to be used?
The least well-defined part is the usage of /photos, but I think it's just an issue of how you define that resource. I'd say that /photos is "The series of photos which the currently authenticated account is permitted to see." Defined that way, the resource makes sense to me.
Taken from the other angle, I think /people/{id}/photos/{id} only makes sense if each person's photos had the same ids—e.g. my photos are /people/1/photos/1,2,3..., and your photos are /people/2/photos/1,2,3... Otherwise, why namespace it at all?
I guess it depends on wether you'll handle photos as a global resource (accessible for all users) or if the photos only exist in one realm at a time, dependent on the authorization.
In my current role', we've gone with the /user/:user_id/assetname/:asset_id pattern, in both the Django server and the Backbone.js router. It just seemed like the right thing to do, and it meant that the user/asset relationship, which exists in the data, is mirrored accurately in the REST architecture.
I tend to agree with Idan: "I'd say that /photos is "The series of photos which the currently authenticated account is permitted to see."" - adding semantics to URL's is a good starting point for API design. And resources doesn't necessarily have to be the same for all users, only the semantics for the resource.
One caveat is in the case where you want to utilize some kind of HTTP caching. When the content at a given URL changes depending on authorization it becomes impossible to cache at the HTTP layer. Not because of the authorization but because the content changes.
I agree with Idan on this for a few reasons. Each photo is its own unique resource while authorization is a filter on top of that resource. Authorization could change - a photo made public, or even transferred to another user. If you include authorization information in the URL transferring ownership becomes messy because the URL should change to include the ID of the new owner. Additionally you don't want to pass out more authorization information than absolutely necessary, especially on something as public as a URL.
I'm going to echo Gavin and Idan and say that each photo is a unique resource and, as such, should have its own unique URI.
That said, since authentication is assumed and everything is private, with no sharing, you could twist the model a little. Ordinarily — perhaps with some parts of the API being shared, and some private — authentication is probably best left as an orthogonal concern, but you could view the service as providing resources under URIs implicitly namespaced by the authenticated user's account. What I mean by that is, since you must be authenticated to use the service, the entire API can be seen as serving only a single user, so that /photos/1 is actually a different resource depending on which user is logged in. The URI is then unique for the unique resource, for me. This would be consistent that /photos returns different resources for different users.
In reality, of course, we know it's serving multiple users, but arguably we can ignore that, as required authentication changes the model somewhat.
But maybe that's just plain nonsense.
Hi Jacob, in my opinion, the second option would be better because URIs should identify uniquely resources (a set of photos). I think HTTP headers "can" determine other aspects to the result but not the requested resource.
Cheers,
Tkm
There's nothing unRESTful about using request headers to adjust the response. REST only requires that everything needed to *understand* the request is included in the request itself. How the identified resource is defined is application-specific. For example, content negotiation allows a single URI to represent multiple translations of a web page, the specific translation to be served is identified by analyzing the Accept-language request header.
As long as the resource at /photos is defined as "the collection of photos belonging to the requesting user" then you have no problem. That doesn't preclude adding sharing later at, e.g. /photos/{username}. As Jacob Atzen pointed out, it is only the semantics of the resource that must be constant, not its contents.
Assuming photo ids are globally unique, then /photos/{id} is a usable scheme. It will return a photo if you are permitted to see it, or a 403 (or maybe 404 if you wanna be sekrit) if not.
I also agree with Idan, Gavin and Adam that every photo should have its unique, stable URI and that the presentation of the collection of resources can depend on the user/authentication.
In one project I did it this way intentionally to make the service look, as if it was all for the authenticated user alone. In /photos the user gets his photos, and in /photos/17 he sees either the photo or a 404. The restful way would be a 403 (forbidden), but I wanted to hide even the fact if there is a photo.id==17 belonging to somebody else or if this photo has been deleted.
Still there is the problem with caching of the collection (say /photos), which should be forbidden when you handle sensitive data (think 'mywebmailer.com/inbox').
Authenticated content (from an HTTP point of view, namely, responses to requests with an 'Authorization' header) is perfectly cacheable by shared caches if the origin allows it, and is always cacheable by non-shared caches (e.g. browser caches) if response would otherwise be cacheable.
Vince has gotten it basically right, which is that you can't design a URI scheme without understanding the semantics of what a client is allowed to do with your API. If you actually build a RESTful API that adheres to "hypermedia as the engine of application state" then URI structure in fact shouldn't matter at all, except for well-known entry points like an API home page.
Since HATEOAS has been mentioned, Steve Klabnik wrote a good summary of REST and how HATEOAS gets missed out in most APIs described as RESTful. http://timelessrepo.com/hat...
Vanity urls (http://myname.photos.com/ph...) would meet all of the requirements above. Headers are not properties of URIs, and one wins if one moves these fields into the URI. (In my example, myname.photos.com would also be in the Host: header, by most user-agents speaking HTTP/1.1)
forget doctrine or notions of semantic purity.
/user/photos/resource is trivial to cache should you ever need to. stick varnish in front with the default rules and i'll "just work".
making URI resources differ based on state in the headers, even authorization, takes more work to cache although it's still not impossible.
This has been touched on, but I don't think it's been made clear...
If photo_id is a system-wide unique identifier, then /photos/{photo_id} is fine. Given a URL like /photos/123, it's a 200 OK if you own that photo, or a 403 Forbidden if you don't.
If photo_id is a per-user scoped identifier (my photos/123 is a different resource to your photos/123) then representing that in a URL like /people/100/photos/123 will be making life easier and more predicable for everybody.
Jacob: did you have a clear idea of whether photo_id is unique scoped to the user or the entire system? Or is that part of the question...
It's a common scenario & I am puzzled as to why the question doesn't come up more often. Obviously, there's not a clear cut right or wrong, but my prefered way is to serve the exact same '/photos' page to everyone. Set a cookie w/ the authorized user's id (note: this is a perfectly RESTful way to use a cookie), send a second XHR request w/ URL that includes the user id to get personalized data with which to "decorate" the page asynchronously (of course that XHR request will need to be authorized). If a single photo is always accessed by one user, go ahead and include the user id in the URL. It all really just comes down to making as full use as possible of HTTP's cache capabilities to improve speed/efficiency.
Interesting question. IMO:
the answer is that the '/photos'+auth = myphotos case can be regarded as RESTful as long as
a) the definitions of the resources are appropriately adjusted (e.g. "a photo collection" -> "a photo collection of the requesting user" as Vince pointed out), and
b) a further assumption is made wrt the resource identifiers: the concept of a resource identifier includes both a URI and an authorization header (which, however, violates Web architecture standards).
According to REST's definition, a resource is a conceptual mapping that can be identified by one or more identifiers, and in one or more equivalent representations whose content may vary in time.
REST also states that a resource identifier essentially identifies a mapping whose semantics should be stable and their semantic validy preserved over time. Now, for a conceptual mapping depending on a qualifier or another identifiable conceptual mapping to be semantically valid, all dependencies should be first addressed (that is, qualifiers should be populated with values and referred mappings identified before being able to identify the initial mapping).
In simpler terms, if two requests by two users to the same 'photos/' URI are done they result into accessing two different resources, and in order to identify the resources the identifier should provide a way to first identify the "requesting user". Otherwise, just 'photos/' URI represents an invalid resource identifier since the mapping is not stable and valid.
To conclude, even if "/photos"+auth header can be regarded as being RESTful under a certain assumption, it is not compliant with the Web architecture (where identification and URIs go together, or at least, they are supposed to).
Everything was said. Though, I'd add an uri "/me" which redirects to /users/$username. Thus, you get both, an unique uri for each ressource and an unique handle that you can easily be used within the browser.
Very good discussion. I prefer the second way. If I had a good english I could explain my opinion. Sorry.
I hate to add one more voice into the morass, but I've implemented this differently in the past:
I'd have a /photos collection, which, depending on user, would have a query parameter "user" that was defaulted to their username. If they attempted to change it, I.E. /photos?user=notme, they'd receive a 403. Unless they were an administrator.
Pros:
One semantic resource, with only one way to access a photos collection.
Useful for admins that might want to search another users photos.
Fairly obvious to a developer what's happening.
You can see an example here, in the bookmarks collection for Readability: https://www.readability.com...
I stay away from web programming when I can. That said, I would include the uid in the url. This may help with bug reports, and it will also help the user if they have multiple accounts: they can check the url to see which id they are logged in with.
The way I tend to look at the URI /people/7/photos is that the originator of the content is user 7. That user could be called the owner, but that doesn't mean that you can't have your authorization layer that uses the identity of the user as verified by the Authorization header, a cookie, or whatever to determine who has the rights to view (or manipulate) the photo.
One beauty of /people/7/photos/1024 is that it is remarkably easy to cache. You can potentially scale the hell out of a solution like this (especially if the content is public) using Akamai, Amazon CloudFront, or other edge caching technologies. This reduces your server load and can reduce your overall costs considerably
If the id for photos is universal to the site. Whoever post get an id+1 of whoever posted before. Then /photos/{id} is perfectly correct.
Now, if {id} for photo is an index by user, then you need
/{userid}/photos/{id}
This is precisely what the Vary header is for.
Leave a comment: