I'm new to node.js and I'm following a tutorial but the code returns an error when I refresh localhost:3000/books
The error:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
Code: app.js
const express = require('express');
const { connectToDb, getDb } = require('./db');
console.log('starting');
// init app & middleware
const app = express();
console.log('init complete');
// db connection
let db;
connectToDb((err) => {
console.log('connecting to db');
if (!err) {
app.listen(3000, () => {
console.log('app listening on port 3000');
});
db = getDb();
} else {
console.log(err);
}
});
//routes
app.get('/books', (req, res) => {
let books = [];
db.collection('books')
.find() // cursor toArray forEach
.sort( { author: 1 })
.forEach(book => books.push(book))
.then(() => {
res.status(200).json(books);
})
.catch(() => {
res.status(500).json({error: 'could not fetch the documents'});
})
res.json({mssg: "welcome to the api"});
});
And db.js:
const { MongoClient } = require('mongodb');
let dbConnection;
module.exports = {
connectToDb: (cb) => {
MongoClient.connect('mongodb://0.0.0.0:27017/bookstore')
.then((client) => {
dbConnection = client.db();
return cb();
})
.catch(err => {
console.log(err);
return cb(err);
});
},
getDb: () => dbConnection
};
I'm hosting the mongodb server with compass: I have a database with the name of bookstore and a collection with the name books In books I have:
[{
"_id": {
"$oid": "636faa18a918cf889958ea12"
},
"title": "Name of wind",
"author": {
"firstName": "Patrick",
"lastName": "Rothfuss"
},
"pages": 500,
"genres": [
"fantassy",
"magical"
],
"rating": 9,
"reviews": [
{
"name": "Ludwig",
"body": "AWESOME!"
}
]
},{
"_id": {
"$oid": "636facd8a918cf889958ea16"
},
"title": "Book of fire?",
"author": {
"firstName": "Willem",
"lastName": "Johnson"
},
"pages": 350,
"genres": [
"fantassy",
"comedy"
],
"rating": 6,
"reviews": [
{
"name": "Ludwig",
"body": "BAD!"
}
]
},{
"_id": {
"$oid": "636facd8a918cf889958ea17"
},
"title": "Thrones of destiny",
"author": {
"firstName": "Jonas",
"lastName": "Adams"
},
"pages": 689,
"genres": [
"magical",
"fantassy"
],
"rating": 10,
"reviews": [
{
"name": "Ludwig",
"body": "The best!"
}
]
},{
"_id": {
"$oid": "636facd8a918cf889958ea18"
},
"title": "Idiots!",
"author": {
"firstName": "Jack",
"lastName": "Phiers"
},
"pages": 486,
"genres": [
"action",
"comedy"
],
"rating": 8,
"reviews": [
{
"name": "Ludwig",
"body": "Great!"
}
]
},{
"_id": {
"$oid": "636facd8a918cf889958ea19"
},
"title": "Where are we?",
"author": {
"firstName": "Jone",
"lastName": "Johnson"
},
"pages": 685,
"genres": [
"magical",
"sci-fi"
],
"rating": 7.6,
"reviews": [
{
"name": "Ludwig",
"body": "Good!"
}
]
},{
"_id": {
"$oid": "63737fae2ea0cb2ca699eec7"
},
"title": "Colour Magic",
"author": {
"firstName": "Terry",
"lastName": "Pretchett"
},
"pages": 768,
"rating": 7,
"genres": [
"fantassy",
"comedy"
]
}]
when logging out the books array I made in app.js its an empty array
CodePudding user response:
The problem is not database.
As the error says Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
, the response is being sent to the client two times.
Two times because, in the app.get() callback, you have these 2 functions running,
res.json({mssg: "welcome to the api"});
and db.collection('books').find()
Both of these are async functions, and hence run parallely.
When node encounters db.collection().find()
it starts to process it asynchronously and moves to the next line, that is res.json()
method.
By the time db.collection().find()
gets completed (since it is a database call, it takes time to execute), the res.json()
would have already finished its execution, and has already sent the response. Now when db.collection().find()
completes, inside the .then()
block, you are sending yet another response to a client which has already received the response {mssg: "welcome to the api"}
Hence the error "Cannot set headers after they are sent to the client"