Skip to content

Instantly share code, notes, and snippets.

@leereamsnyder
Last active October 20, 2017 17:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save leereamsnyder/3df5ce766f06841745bc to your computer and use it in GitHub Desktop.
Save leereamsnyder/3df5ce766f06841745bc to your computer and use it in GitHub Desktop.
Detect if a request in Express is for HTML or JSON
/*
Usage:
var jsoncheck = require('./wantsJSON') // path to file with this middleware function
app.use(jsoncheck)
app.get('/', function(req,res,next){
if (req.wantsJSON) {
// serve JSON
}
if (req.wantsHTML) {
// serve HTML
}
})
But feel free to just scan the code and the bits you need
The Middleware below is super simple, but Google was letting me down
Here's what I was after: sometimes, clients, including browsers, would be requesting HTML,
and other times JSON, and I needed a simple way to detect between them.
This was surprisingly tough!
Some folks recommended using req.xhr http://expressjs.com/api.html#req.xhr
However, req.xhr only checks if the request’s “X-Requested-With” header field is “XMLHttpRequest”
In that situation, there's a solid chance the client wants JSON, but that's not a guarantee!
Maybe you'd think, "I could look for 'html' in the Accepts header!"
Solid theory!
Well, here's Internet Explorere's Accept header when requesting a web page:
> image/jpeg, application/x-ms-application, image/gif,
> application/xaml+xml, image/pjpeg, application/x-ms-xbap,
> application/x-shockwave-flash, application/msword, * /*
Note that "text/html" isn't there.
Yes, a web browser doesn't specify that it might be keen on HTML ( ._.)
Other things I found recommended using req.accepts('json')
However, if the client indicates they accept * / *, that says "hey JSON is OK!",
so req.accepts('json') will return "json" instead of undefined
You'll see this with most browsers: they have * / * in the Accepts header when requesting a web page.
The trick is to use req.accepts(), but specify both 'html' and 'json' IN THAT ORDER.
req.accepts('html','json') says, more or less:
Given the Accepts headers on this request (which take order into account),
AND given a choice between matching 'html' or 'json',
AND I prefer 'html', (based on the order of arguments)
which would be the best match?
That covers you:
browsers that accept text/html return "html"
IE that accepts * return "html"
If a request explicitly puts application/json before text/html or *, it'll get "json"
And that's probably what you want
*/
module.exports = function(req, res, next){
req.wantsJSON = req.accepts('html','json') === 'json';
req.wantsHTML = req.accepts('html','json') === 'HTML';
}
@andrewsosa
Copy link

Looks like you might have a typo on line 57 – you've got res in there twice. I'm guessing the first one is supposed to be req?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment