The Accept Header

31 May 2011

Years ago, I wrote a book on HTTP. At the time, there wasn't a simple, comprehensive reference for HTTP beyond the various specs, and a really good understanding of HTTP is important if you want to become a really good web developer, which I did. As I was reading and learning everything I could, I was surprised to learn that such a book didn't already exist.

Fast forward to today, and I can barely remember what I wrote. :-) One of the things I always struggle to remember is how to parse the Accept header. The spec has some examples you can use to refresh your memory, but I've never found RFCs to be a quick read, even when I know what I'm looking for.

Here's an example, the Accept header my browser sends:

  1. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,application/json

It would be a little easier to read with some spaces:

  1. Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8, application/json

Here's a quick reference for how to interpret the Accept header:

Here's the breakdown of this particular example:

It's common for the most preferred type to be listed first, with no quality specified.
XHTML served as application/xhtml+xmlis the next type that shares the highest preference. (This site serves XHTML as text/html. You can read more about this decision in the colophon.)
XML has a quality of 0.9, indicating a high preference, but not as preferred as HTML and XHTML.
Asterisks are wildcards, so */* matches any type. This is similar to saying anything is fine, but the other types are preferred, because this is given the lowest quality.
I use JSONovich, which explicitly adds application/json as a supported media type.

It's the support for application/json that prompted me to blog about this. I've noticed a recent trend that affects sites with APIs when JSON is one of the supported formats. The trend is best shown by example. Here's what I see when I visit Netflix:

Netflix fails

Just a few days ago, I would see a web site. Now I see JSON. Pretty crazy, right?

Netflix isn't the first site to make this mistake; it's just the most recent. I experimented a bit to see if I could figure out what they were doing wrong, and I was disappointed with what I found. Would lowering the quality of application/json all the way to 0.0 make a difference?

  1. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,application/json;q=0.0

Nope, still JSON. The mere presence of the string "json" anywhere in the Accept header seems to be enough to cause the problem. The Accept header might be hard to read and parse, but they're not even trying.

I'd love to know why this is becoming more and more common. Is there a broken content negotiation example somewhere that everyone is using? I'm really curious.

I've reported the problem to Netflix via phone and Twitter. Hopefully they'll fix it soon.