On Apr 7, 2014, at 12:24 AM, Felix Meschberger wrote: > TL;DR: Use Accept header to set request's selectors and extension. So an > example Accept content type of "application/x-players+json" would set the > selector string to "players" and the extension to "json". > > We always touted Sling to be a platform for REST-ful web applications. But we > cheated a bit in that we "invented" request selectors and extensions for > content negotiation instead of using the HTTP Accept header. The reason for > this cheating was pure pragmatism since in Browsers the easy way to influence > requests is basically just URLs and request parameters. > > Hence we built all request processing, prominently script/servlet selection > on these selectors and extensions. And this proved highly effective. > > Still, trying to define "pure" REST-ful APIs we can assume applications to be > able to set the HTTP Accept header and to be able to define clean URLs > without selectors and extensions.
I think this is confusing REST with several other concepts. For example, "Cool URIs don't change" is a principle that TimBL often talks about, but it is orthogonal to REST. It is important for bookmarks, home pages, and reference longevity. REST requires that all important resources be identified; it doesn't say one kind of URI is better than another. It certainly doesn't say that proactive content negotiation is better than non-negotiated resources, since the latter is far superior for caching. What it does say is that a negotiated resource is not the same resource as a non-negotiated resource, since they do not have the same expectations. And there is no such thing as an impure RESTful API. An application is either designed according to REST or it isn't, and an API either supports that or it doesn't. > So for a browser we want to support something like: > >> GET /teams/fcbasel.html HTTP/1.0 >> Host: soccer.example.com > > while for REST-ful APIs more something like: > >> GET /teams/fcbasel HTTP/1.0 >> Host: soccer.example.com >> Accept: application/x-players+json You might want to support that for the sake of having a content negotiated identifier, but it isn't any more RESTful than the first example. In general, x- is not an appropriate prefix for media types. Sling should not encourage their use. > What if Sling would convert the Accept content type > "application/x-players+json" into > >> selectors = [ "players" ] >> selectorString = "players" >> extension = "json" > > This could be done in the Sling Engine's SlingRequestPathInfo constructor > under the following conditions: > > * Extension (and optional selectors) have not derived from the URL yet > * Accept header has a single content type (Browsers generally send a list of > supported types) > * Accept header is an application type > * The sub type is converted to selector and extensions, where "+" is used as > the separator > > WDYT ? I think being able to route requests to resources based on negotiation header fields (or any request header field) is useful, but beware of how this impacts access control by location. It is important that the server not lose track of the fact that it received "/teams/fcbasel" as the request target, which might have different access controls than "/teams/fcbasel.players.json". This can be a problem in deployments where an external server (gateway) performs security checks based on the request target if that server is unaware that the application server will reinterpret the request based on the Accept field's value. For example, consider when the origin server has /teams/fcbasel.players.json /teams/fcbasel.private.json and they have different authentication requirements (outside Sling). We don't want the client (attacker) to be able to bypass access controls by manipulating the (typically uncontrolled) Accept field value. Note that this kind of resource resolution also requires that a Vary header field be set in the response. What httpd does is allow a URI (or directory) to have an option set for multiviews (or some other negotiation mechanism), which is invoked only if the request target is not found. This allows negotiated and non-negotiated resources to exist in the same place with the non-negotiated resource winning any request that might be ambiguous. Regardless, please note that the notion of RESTful systems preferring proactive content negotiation is a myth. If anything, RESTful systems prefer reactive negotiation, client-side scripting (code on demand), or specific relationship names as a means of selecting from multiple variant URIs. In other words, more links, with the client choosing the one that best fits their purpose/understanding/version. Cheers, Roy T. Fielding <http://roy.gbiv.com/> Senior Principal Scientist, Adobe <http://www.adobe.com/>