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:
http://expressjs.com/api.html
And there are two methods req.accepts() and req.is(), used like this:
req.accepts('json') 
or
req.accepts('html') 
Since these are not working as they should, I tried using:
var requestType = req.get('content-type');
or
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.8JSON :
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.
//client 
.jstree({
            // List of active plugins
            "plugins" : [
                "themes","json_data","ui","crrm","cookies","dnd","search","types","hotkeys","contextmenu"
            ],
            "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"
                    }
                }
            }
        })
                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.
EDIT:
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
}
                        It's a bit later, but I found this a better solution for me:
req.accepts('html, json') === 'json'
Hope it helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With