Should there be a standard X-Ajax-Engine request header?
Posted in mochikit, dojo, ajax, prototype Fri, 30 Jun 2006 17:49:00 GMT
A little while ago I was looking at JSON and Catalyst::View::JSON (a server-side library to provide some JSON repsonse magic for Catalyst) and I discovered that AJAX libraries auto-eval JSON differently, Dojo looks in the response body and Prototype looks in the X-JSON header (read about X-JSON problems with IE 6). This got me thinking that there's no standard way for the server to tell what kind of AJAX library is making the request. Prototype sets the X-Requested-With and X-Prototype-Version as:
var requestHeaders = ['X-Requested-With', XMLHttpRequest', 'X-Prototype-Version', Prototype.Version,
For Dojo, some people are manually sending a request header along the lines of isDojo:true. MochiKit doesn't currently send an identifier.
I tend to prefer a bit more information such as the library version. Does it make sense for AJAX libraries to send a standard User-Agent along the lines of X-XMLHttpRequest-User-Agent (X-AJAX-User-Agent is shorter but may not be as correct; subsequent to the initial post, a discussion with Alex Russell generated the X-Ajax-Engine name which has been incorporated below). Something shorter is preferable but this is just an initial proposal. It would also remove the need for Prototype's separate X-Requested-With header since having X-Ajax-Engine set at all would indicate XMLHttpRequest. The format could follow the one established for User-Agent:
X-Ajax-Engine: <library_name>/<library_version>
This can be done manually with Dojo, MochiKit and Prototype as follows:
// in a Dojo.io.bind call: headers: { 'X-Ajax-Engine':'Dojo/'+dojo.version }
// for MochiKit: req.setRequestHeader( 'X-Ajax-Engine', 'MochiKit/'+MochiKit.Async.VERSION )
// in a Prototype AJAX.Request call: requestHeaders: [ 'X-Ajax-Engine', 'Prototype/'+Prototype.Version ]
Optional information could be added in parenthesis afterwards, e.g. Dojo Toolkit could include the edition name or something along the lines of "Custom Build" like (I'm not sure if other libraries have a reason to do this):
X-Ajax-Engine: Dojo/0.3.1 (BrowserIO)
If client libraries started using this or something similar, server-side identification could start (attempting to) depend on something that was standardized. Standardization can even be proposed as an addition to the W3C's XMLHttpRequest efforts. I think standardization would be great because it will probably happen eventually and for now it would make server-side identification more reliable.
UPDATE 1: Less than a week after I posted this, a related issue came up on the MochiKit Google Group involving adding a X-MochiKit-Version header to mimic X-Prototype-Version. I put in a word for standardization and after discussing this with Alex Russell (see below) posted back to the group. Seems like we may get a defacto standardization on X-Ajax-Engine which would be nice.
UPDATE 2: I spoke to Alex Russell of Dojo Toolkit about this and he thought this is a good idea. Apparently if you set sendTransport in dojo.io.bind, an identifier (but not version number) will get sent, however it seems not many people know about this. We discussed shorter names and Alex came up with X-Ajax-Engine. He mentioned he could bring this up at the OpenAjax Alliance.
Perhaps, what is really interesting isn’t which library that made the request. What is interesting, is what type of data it expects returned. This is really a Content-Type issue. There are the passive data formats such as html-fragments, xml and json, but then there are the fragments of javascript that needs to be eval’ed. This is where it becomes important if the caller is the one or other library, because eval’ed code will have to make assumptions about the framework. One could argue that returning code for eval is a bad idea in the first place, but if you must, why not mark it with a custom content-type. For example Content-Type: application/x-javascript-prototype (or whatever). And the caller (The XmlHttpRequest) could request the specific type in the Accept header.
It’s not necessarily just a Content-Type issue because Prototype and Dojo can both request the application/json Content-Type but expect different responses. Prototype will want the JSON in the X-JSON header and Dojo will want the JSON in the response body.
I really dislike the idea of a custom content type and much prefer standardization. There are probably over 50 AJAX libraries out there. Having a custom content-type for each one can become hard to support IMO.
OK, so it goes a little further than just the content-type. Still – What we want to communicate, is the expected format of the response, and Content-Type almost covers this. In the case of prototype, expecting the response in a header-field, is really prototype breaking with the spirit of the http protocol – It should have recieved it’s response in the body.
Either way, I think that X-Ajax-Engine is misleading. The server shouldn’t be concerned with whom sent the request. Rather it should be concerned with what type of request the client expects. For example, I might write my own ajax-client, that knows how to handle dojo-formated response, even though it’s not dojo. So if anything, the header should be named X-Ajax-Response-Type
I also fail to see the difference between sending 50 different X-Ajax-Engine values or sending 50 different custom content-type’s. I don’t see how one is more standard than the other. In fact, I think it would be more in lieu with http to use Content-Type to communicate content type, rather than making up a new field for basically the same information.
Perhaps the proposal needs to allow for ‘compatible’ which is how MSIE does user agent. Also, if you have a Dojo-compatible library, there’s also nothing to prevent your library from masquerading as Dojo or another library, which ‘compatible’ was intended to do.
I don’t like extending content types to include the library name/type because (a) libraries can change between versions so you’d also need the version number in the content type, e.g. application/json-dojo-0.3.3 and (b) content types traditionally don’t have library names and version numbers, just type/subtype. There are lots of applications that process content types including the MIME::Type CPAN module. Overloading content type this way may require many applications and libraries to be updated with the ability to strip off the library name and possibly the version number. I’d have to look at the content type spec more to see if extensions beyond type/subtype are allowed (so far I’ve only seen type/subtype), but I think overloading it in this, somewhat unexpected, way is asking for trouble.
merci frere