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/>

Reply via email to