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:
Checking the node server showed the same thing - DELETEs were returning status 1.
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.