res.json() vs res.send() vs res.end() in Express
Older Article
This article was published 8 years ago. Some information may be outdated or no longer applicable.
Express is one of the most popular web frameworks for Node.js. Most Node.js developers have used it at some point. It’s got a pile of HTTP utility methods, and it performs well.
When you work with Express, you get access to a request and a response object. The response object gives you several ways to send data back: res.json(), res.send(), and res.end(). The question that keeps coming up: how are these different? Let’s walk through them.
Response
Whenever an Express app receives an HTTP request, it hands the developer an object commonly called res. Here’s a bare-bones example:
app.get('/api/test', (req, res) => {
// ... do something ...
});
The res object is an enhanced version of Node.js’s native response object.
Sending a response
There are multiple ways to send responses with Express. Let’s go through them.
res.send()
Call res.send() to send a response. Its signature looks like this: res.send([body]), where the body can be a Buffer, String, Object, or Array.
This method sets the Content-Type response header automatically based on what you pass in. Hand it a Buffer and the Content-Type becomes application/octet-stream (unless you’ve set it to something else manually).
You can set the
Content-Typeheader yourself viares.set('Content-Type', 'text/html');.
Many developers use Express to build RESTful APIs, and most of those APIs return JSON. So the question surfaces: should you use res.send() to return JSON data (since it accepts objects), or should you use res.json()?
Let’s see what happens when we send JSON data:
app.get('/api/test', (req, res) => {
res.send({ hello: 'world' });
});
The response header:
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
Content-Length: 17
ETag: W/"11-IkjuL6CqqtmReFMfkkvwC0sKj04"
Date: Fri, 10 Aug 2018 09:34:13 GMT
Connection: keep-alive
Express correctly sets the Content-Type. So if that works, why does res.json() exist at all?
res.json()
res.json() has extra functionality tied specifically to JSON. It can format the returned data using two options:
app.set('json replacer', replacer); // property transformation rules
app.set('json spaces', 2); // number of spaces for indentation
These options get passed to JSON.stringify(), whose signature is: JSON.stringify(object, replacer, space). After calling JSON.stringify(), res.json() then calls res.send() under the hood.
Last, let’s look at res.end().
Take a look at this article to see what happens when you don’t call
res.end(): Concurrent HTTP connections in Node.js
res.end()
This method ends the response. But do you always need it? The answer: sometimes yes, sometimes no.
You’d use res.end() when you want to end the response without sending any data. A 404 page, for example:
res.status(404).end();
Here we set the HTTP status code explicitly and close the response right after.
But if you want to send data and end the response? Both res.send() and res.json() handle that for you. They send the data and close the response, so there’s no need to call res.end() separately.
res.end()doesn’t send an ETag header with the HTTP response, whileres.send()does. That Entity Tag header matters for web cache validation. It helps caches work more efficiently and saves bandwidth.
Conclusion
To sum it up: res.json() gives you extra JSON formatting options. If you don’t need those, res.send() works perfectly fine for returning response objects. Both methods also close the response for you. No extra steps needed.