When a browser (or any web client) requests content from a web server, it can tell the server what types of content type it can interpret (HTML, text, audio, etc.). The underlying HTTP protocol allows these to be specified via “header” settings—metadata that is sent before any actual content, describing characteristics about the content. The browser can send an “Accept” header—to describe what it accepts—and the server responds with a “Content-type” header. The Accept header can be quite elaborate, but what happens when what happens when these conflict?
This is usually of concern when writing server-side code, and particularly, a framework. Because most developers do not write frameworks (they use one) and since they control both the client and server-side code, they rarely need to concern themselves with this. But I have been thinking through such minutia as I write my own PHP framework. In particular, there are lots of characteristics about a request to a server that can be handled (i.e., routed) by a server framework. It is common for a server to be able to deliver the same essential content but can be encoded in different ways, HTML, XML, JSON—different formats for the same content. Because developers do not usually consider the Accept header during development, they construe other methods of specifying to a server what format is desired; e.g., by the document name or URL:
|Type||By Doc Name||By URL Path||By Query Value|
often the default
While these methods are fine, there is no standard for these approaches. This means that the developer has to contrive their own way of correlating those names to the format request type. The Accept header is already a standard way to accommodate this. The W3C spec describes the format and interpretation of the Accept header pretty well in “Chapter 14.1 Header Field Definitions: Accept” (though it took me a long time for its relevance to sink in). The complication is that the Accept header is fairly elaborate and frameworks don’t route to code based on these settings. Also, it is often inconvenient to set the Accept header from the caller (though, I am going to ignore this last point for the purposes of this article).
The Accept header specifies the type of data they accept using MIME-types and subtypes (e.g., text/html, application/xml). The Accept header allows for multiple specifications of content it will accept as well as a priority for them:
Accept: text/html, text/*, text/plain; q=.5, */*
which says that the client is
- preferring HTML for a given (URL) request,
- if that isn’t available from the server, send text/plain formatted content,
- if that isn’t available, send any text type content,
- and, finally, if that isn’t available, send any other content type the server has.
If “*/*” were not part of the specification and the server did not have any of the other format types available, then the server should return a 406 error response.
So, rather than contriving a URL specification for a client to specify in order to identify the type of data to receive, I want to build a framework to interpret the Accept setting and dispatch to the appropriate “handler” for the request. I am not sure, yet, how to do this in a way that is predictable and easy to use for the developer and does not conflict with other dispatching decisions they may also have. Part of the problem is that the Accept spec can be open-ended and its relationship between what the client wants and what the server can deliver is many-many.
Perhaps, a server framework would allow a priority of types to deliver which, in combination with the Accept specification, would determine the handler to dispatch to.
Comments? How would you like to see a framework automatically handle these decisions?