NodeJS : Validating request type (checking for JSON or HTML)


I would like to check if the type that is requested by my client is JSON or HTML, as I want my route to satisfy both human and machine needs.

I have read the Express 3 documentation at:

And there are two methods req.accepts() and, used like this:




Since these are not working as they should, I tried using:

var requestType = req.get('content-type');


var requestType = req.get('Content-Type');

requestType is always undefined...

Using the suggestion at this thread:

Express.js checking request type with .is() doesn't work

does not work either. what am I doing wrong?

Edit 1: I have checked for correct client HTML negotiation. Here are my two different request headers (taken from the debugger inspector):

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

JSON : Accept: application/json, text/javascript, */*; q=0.01

Solution (thanks to Bret):

Turns out I was specifying the Accept headers wrong, and the */* was the issue. Here is the code that works!

//server (now works)
var acceptsHTML = req.accepts('html');
var acceptsJSON = req.accepts('json');

if(acceptsHTML)  //will be null if the client does not accept html

I am using JSTREE, a jQuery plugin that uses jQuery Ajax calls underneath). The parameters passed to the Ajax call are in the "ajax" field, and I have replaced the "accepts" parameter with a complete "headers" object. Now it works, and should solve the problem when you are using plain jQuery if it should ever occur.


            // List of active plugins
            "plugins" : [

            "json_data" : {
                "ajax" : {
                    // the URL to fetch the data
                    "url" : function(n) {
                        var url = n.attr ? IDMapper.convertIdToPath(n.attr("id")) : "<%= locals.request.protocol + "://" + locals.request.get('host') + locals.request.url %>";
                        return url;
                    headers : {
                        Accept : "application/json; charset=utf-8",
                        "Content-Type": "application/json; charset=utf-8"
Problem courtesy of: João Rocha da Silva


var requestType = req.get('Content-Type'); definitely works if a content-type was actually specified in the request (I just re-verified this a minute ago). If no content-type is defined, it will be undefined. Keep in mind that typically only POST and PUT requests will specify a content type. Other requests (like GET) will often specify a list of accepted types, but that's obviously not the same thing.


Okay, I understand your question better now. You're talking about the Accept: header, not content-type.

Here's what's happening: notice the */*;q=0.8 at the end of listed accept types? That essentially says "I'll accept anything." Therefore, req.accepts('json') is always going to return "json" because technically it's an accepted content type.

I think what you want is to see if application/json is explicitly listed, and if so, respond in json, otherwise respond in html. This can be done a couple of ways:

// a normal loop could also be used in place of array.some()
if(req.accepted.some(function(type) {return type.value === 'application/json';}){
    //respond json
} else {
    //respond in html

or using a simple regular expression:

if(/application\/json;/.test(req.get('accept'))) {
    //respond json
} else {
    //respond in html
Solution courtesy of: Bret Copeland


It's a bit later, but I found this a better solution for me:

req.accepts('html, json') === 'json'

Hope it helps!

Discussion courtesy of: joserobleda

Please define "not working as they should", because they do for me.

In other words:

// server.js
console.log('Accepts JSON?', req.accepts('json') !== undefined);

// client sends 'Accept: application/json ...', result is:
Accepts JSON? true

// client sends 'Accept: something/else', result is:
Accepts JSON? false

The Content-Type header as sent by a client isn't used for content negotiation, but to declare the content type for any body data (like with a POST request). Which is the reason why isn't the correct method to call in your case, because that checks Content-Type.

Discussion courtesy of: robertklep

This recipe can be found in it's original form on Stack Over Flow.