Node.js and Express - Strange Http Status Codes

Posted on | 527 words | ~3 mins
Express.js JsonClient Node.js Json Javascript

In a Nutshell

Sending a response in Express with a call like res.send(status, body) will send body as the status code if it is numeric - ignoring status. This is due to a fudge for backwards compatibility.

The Details

As part of a project I'm working on, I'm writing a service using node.js and Express. This service exposes some entities in a MongoDB database through a REST API. Typically I hit this API through client-side Javascript, but in some places I want to hit the same API from some C# code - and I don't want to have to create classes for everything. I've got a funky library for this which I'll be publishing soon, but it helped me find a problem.

Testing the C# code showed me something that was a bit odd - GETs and POSTSs were working fine, but PUTs and DELETEs were showing an HTTP Status code of ‘1’ (which isn’t a valid code). Here’s the what I was seeing:

requests

Checking the node server showed the same thing - DELETEs were returning status 1.

console

The server code is very lightweight so it’s quick to see what’s going on:

[code lang=“js”]exports.deleteUser = function(request, response) {

//	Get the id.
var id = request.params.id;

//	Log the user id.
console.log('Deleting user: ' + id);

//	Get the users collection, delete the object.
db.collection(collectionName, function(err, collection) {
    collection.remove({'_id':new BSON.ObjectID(id)}, {safe:true}, function(err, result) {
        if (err) {
            console.log('Error deleting user: ' + err);
            response.send(400, {'error':'An error has occurred'});
        } else {
            console.log('' + result + ' document(s) deleted');
            response.send(result);
        }
    });
});

}[/code]

The function is called successfully, so we hit ‘response.send’. This looks like the problem - the result object is simply the number one, checking the Express Api Documentation for send shows some examples like this:

res.send(new Buffer('whoop'));
res.send({ some: 'json' });
res.send('some html');
res.send(404, 'Sorry, we cannot find that!');
res.send(500, { error: 'something blew up' });
res.send(200);

So just like the final example, we’re sending the code 1, which is not valid. What surprised me was what happened when I changed the send call to the below:

[code lang=“js”]response.send(200, result)[/code]

I was still getting the code 1 returned. It turns out that this is a kind of undocumented oddity of Express - if you pass a numeric code and the second argument is also numeric it sends the second argument as the status.

In response.js of Express we find:

[code lang=“js”]res.send = function(body){ var req = this.req; var head = ‘HEAD’ == req.method; var len;

// allow status / body if (2 == arguments.length) { // res.send(body, status) backwards compat if (’number’ != typeof body && ’number’ == typeof arguments[1]) { this.statusCode = arguments[1]; } else { this.statusCode = body; body = arguments[1]; } }[/code]

So it seems the Express used to support a call like res.send({body}, 200) - and checks for a numeric second argument for backwards compatibility.

The workaround - don’t send numbers as any part of the response, unless it’s most definitely the status code - if you want to return the number of documents deleted, format it as json first, otherwise Express will get confused and mess with your status codes.