What is the difference between res.end() and res.send()? - node.js

I'm a beginner in Express.js and I'm confused by these two keywords: res.end() and res.send().
Are they the same or different?

First of all, res.send() and res.end() are not the same.
I would like to make a little bit more emphasis on some key differences between res.end() & res.send() with respect to response headers and why they are important.
1. res.send() will check the structure of your output and set header
information accordingly.
app.get('/',(req,res)=>{
res.send('<b>hello</b>');
});
app.get('/',(req,res)=>{
res.send({msg:'hello'});
});
Where with res.end() you can only respond with text and it will not set "Content-Type"
app.get('/',(req,res)=>{
res.end('<b>hello</b>');
});
2. res.send() will set "ETag" attribute in the response header
app.get('/',(req,res)=>{
res.send('<b>hello</b>');
});
¿Why is this tag important?
The ETag HTTP response header is an identifier for a specific version of a resource. It allows caches to be more efficient, and saves bandwidth, as a web server does not need to send a full response if the content has not changed.
res.end() will NOT set this header attribute

First of all, res.send() and res.end() are different.
res.send() will send the HTTP response. Its syntax is,
res.send([body])
The body parameter can be a Buffer object, a String, an object, or an Array. For example:
res.send(new Buffer('whoop'));
res.send({ some: 'json' });
res.send('<p>some html</p>');
res.status(404).send('Sorry, we cannot find that!');
res.status(500).send({ error: 'something blew up' });
See this for more info.
res.end() will end the response process. This method actually comes from Node core, specifically the response.end() method of http.ServerResponse. It is used to quickly end the response without any data. For example:
res.end();
res.status(404).end();
Read this for more info.

res.send() implements res.write, res.setHeaders and res.end:
It checks the data you send and sets the correct response headers.
Then it streams the data with res.write.
Finally, it uses res.end to set the end of the request.
There are some cases in which you will want to do this manually, for example, if you want to stream a file or a large data set. In these cases, you will want to set the headers yourself and use res.write to keep the stream flow.

In addition to the excellent answers, I would like to emphasize here, when to use res.end() and when to use res.send() this was why I originally landed here and I didn't found a solution.
The answer is very simple.
res.end() is used to quickly end the response without sending any data.
An example for this would be starting a process on a server:
app.get(/start-service, (req, res) => {
// Some logic here
exec('./application'); // dummy code
res.end();
});
If you would like to send data in your response then you should use res.send() instead:
app.get(/start-service, (req, res) => {
res.send('{"age":22}');
});
Here you can read more:
http://expressjs.com/en/4x/api.html#res.end
http://expressjs.com/en/4x/api.html#res.send

res.send() is used to send the response to the client where res.end() is used to end the response you are sending.
res.send() automatically call res.end() So you don't have to call or mention it after res.send()

res is an HttpResponse object which extends from OutgoingMessage. res.send calls res.end which is implemented by OutgoingMessage to send HTTP response and close connection. We see code here

Related

How to get response body from Express.js server using Supertest?

I started to write some tests for my application and I have issues to read/get response from the server. I tried many things but nothing really worked, can someone help me please ?
// /api/checkCreds
exports.checkCreds = async function(req, res){
//validation
if(!await User.checkCreds(req.body.username, req.body.password)){
var result = {error: true, data: "Incorrect"}
res.sendStatus = 401;
return res.send(JSON.stringify(result));
}
If credentials sent to the server aren't matching, return a response with "Incorrect" message back to the user.
In the test I'm trying to get data from the server to check if properties are matching the expected output.
//test.js
it("We should fail with HTTP code 401 because incorrect data is passed (username='incorrect' password='incorrect')", function(done){
supertest(app)
.post('/api/checkCreds')
.send({username: 'incorrect', password: 'incorrect'})
.expect({error: true, data: "Incorrect"})
.expect(401, done);
});
When ran, test fails because expected properties are different from the response sent by the server, which is an empty object {}.
Any help is appreciated.
You may try changing your first expect to see if you can coax supertest into showing you the actual body that it's comparing to. For example, expect('')
If that doesn't work, there's a version of expect that accepts a function. In that function, you should be able to print out what you are getting in the response body, ie. console.log(res).
It may be that there's some confusion with the JSON return type-- I haven't used that directly. You could try expecting JSON.
Finally, there's a strange paragraph in the documentation that I don't think applies, but I thought I'd mention:
One thing to note with the above statement is that superagent now sends any HTTP error (anything other than a 2XX response code) to the callback as the first argument if you do not add a status code expect (i.e. .expect(302)).
While trying to fix my issue, I noticed that in the HTTP response, Content-Type header was set to text/plain and my server was returning JSON, so that probably was the thing that confused supertest.
I think that res.send() sets the header to text/plain by default and I had to manually set the header value to application/json by using res.type('json'). At that point I was able to read the response body without an issue.
I also learned that res.json() sets the Content-Type header to application/json by default, so you don't need to do it manually like with res.send().
Working code:
// /api/checkCreds
if(!await User.checkCreds(req.body.username, req.body.password)){
var result = {error: true, data: "Incorrect"}
return res.status(401).json(result);
}
//test.js
it("We should fail with HTTP code 401 because incorrect data is passed (username='incorrect' password='incorrect')", function(done){
supertest(app)
.post('/api/checkCreds')
.set('Content-type', 'application/json')
.send({username: 'incorrect', password: 'incorrect'})
.expect(401)
.expect(function(res){
console.log(res.body);
})
.end(done);
});
Feel free to correct me if I stated something that isn't quite right.

Check if res is sent / ended with Express

Using Express, how can I determine the response has been sent / that the response has been completely written to?
app.use((req,res,next) => {
if(res.ended){
//
}
if(res.finished){
//
}
});
how can I tell if res.end() has been called? I am looking for a boolean I can read on res.
Use res.writableEnded (docs).
res.finished is deprecated (see).
response.end() will set response.finished if it's been called, as per the documentation.

Error: Can't set headers after they are sent because of res.?

I'm trying to set up a method that is called with Shopify's webhook. I get the data and I'm able to store with a fresh server but I get "Error: Can't set headers after they are sent" returned in the console. I believe this is because I'm calling res twice. Any ideas on how to structure this better?
This is my method:
function createProductsWebHook(req,res,next) {
//if(req.headers){
// res.status(200).send('Got it')
// return next()
// }
res.sendStatus(200)
next()
const productResponse = req.body
console.log(productResponse)
const product = Product.build({
body_html: req.body.body_html,
title: req.body.title,
});
product.save()
.then(saveProduct => res.json(saveProduct))
.catch((e)=> {
console.log(e)
});
}
This occurs because the middleware, createProductsWebHook(), is called first when a request is received, which then sends a 200 status code response, res.sendStatus(200). Then in, in the same middleware function, product.save().then(...) is called. save()’s callback function attempts to send a response too – after one has already been sent by the very same middleware – using res.json(saveProduct).
Key Takeaway
Middleware should not send the response; this defeats the purpose of middleware. Middleware's job is to decorate (add or remove information, i.e, headers, renew some auth session asynchronously, perform side effects, and other tasks) from a request or response and pass it along, like a chain of responsibility, not transmit it – that's what your route handler is for (the one you registered your HTTP path and method with, e.g., app.post(my_path, some_middleware, route_handler).

NODEJS - Can't set headers after they are sent

I have function, that executes when 'dataCompiled' event fires, it looks like his:
eventEmitter.on('dataCompiled', function () {
json = JSON.stringify({
conversations: convs
});
res.json(json).end();
return;
});
But when i refreshing page, i getting error
Error: Can't set headers after they are sent.
Finally figured out, need send json directly to end function, so it'll look like that:
res.end(json);
You don't need to stringify and end a call to res.json if I'm not mistaken:
eventEmitter.on('dataCompiled', function () {
return res.json({
conversations: convs
});
});
Are you sure you're not sending more data after this call? You shouldn't have to use res.end(): http://expressjs.com/en/4x/api.html#res.end .
If there is another place in your code you're sending more data to res it will give the error message you are receiving, res.end is not fixing the underlying problem.

Clearing Cooking in Express

I am setting a cookie like below in a post function.
res.cookie('sessionID', req.sessionID, { path: '/' });
It sets it fine...but I cannot seem to delete it. I am deleting it in a put function, because I want to update some data and then clear the cookie.
app.put('/data/completed/:info', jsonParser, function(req, res){
if (!req.body) return res.sendStatus(400)
res.clearCookie('sessionID', { path: '/' });
console.log(req.cookies.sessionID);
});
Obviously I am doing something wrong I just can't figure out what.
You are clearing cookie of response. But checking for request. Try to check console.log(res.cookies.sessionID);
So the issue wasn't with the clearing of the cookie it was with me not ending the response process. As clarified on the Express documentation.
res.end([data] [, encoding])
Ends the response process. This method actually comes from Node core,
specifically the response.end() method of http.ServerResponse.
Use to quickly end the response without any data. If you need to
respond with data, instead use methods such as res.send() and
res.json().
So when I put the res.end() function in the code, everything works as expected and the cookie clears.
app.put('/reset/:completed',function(req,res){
res.clearCookie('sessionID', { path: '/' });
res.end();
});

Resources