I'm new to mongoDB, Nodejs and express your helps would be more appreciated.
In below code i'm trying to find and get the remaining count from the collection model "examConfigModel" by passing the examcode, and there is check for remaining count if its greater the 0 then find another collection model "examRegisterModel" based on examcode and then there is a check to avoid duplicate entry to DB. If its unique then save the document else return error message "message:"Already Registered"". But after running the code the save is working fine but i'm getting below error and node server will stop.
Please help me how can i deal with multiple queries within a query.
Error: Can't set headers after they are sent.
at validateHeader (_http_outgoing.js:491:11)
at ServerResponse.setHeader (_http_outgoing.js:498:3)
at ServerResponse.header (C:\practice\angular2\student-reg-app\node_modules\express\lib\response.js:767:10)
at ServerResponse.send (C:\practice\angular2\student-reg-app\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (C:\practice\angular2\student-reg-app\node_modules\express\lib\response.js:267:15)
at C:\practice\angular2\student-reg-app\server\routes\api.js:208:17
at C:\practice\angular2\student-reg-app\node_modules\mongoose\lib\model.js:4495:16
at model.$__save.error (C:\practice\angular2\student-reg-app\node_modules\mongoose\lib\model.js:396:7)
at C:\practice\angular2\student-reg-app\node_modules\kareem\index.js:315:21
at next (C:\practice\angular2\student-reg-app\node_modules\kareem\index.js:209:27)
at Kareem.execPost (C:\practice\angular2\student-reg-app\node_modules\kareem\index.js:217:3)
at _cb (C:\practice\angular2\student-reg-app\node_modules\kareem\index.js:307:15)
at $__handleSave (C:\practice\angular2\student-reg-app\node_modules\mongoose\lib\model.js:310:5)
at C:\practice\angular2\student-reg-app\node_modules\mongoose\lib\model.js:193:7
at result (C:\practice\angular2\student-reg-app\node_modules\mongodb\lib\utils.js:414:17)
at session.endSession (C:\practice\angular2\student-reg-app\node_modules\mongodb\lib\utils.js:401:11)
Below is the code please help me if not clear with my Question please let me know i will provide more details.
const express = require('express');
const router = express.Router();
const mongoose = require('mongoose');
const usersSchemaModel = require('../models/users-schema');
const statesSchemaModel = require('../models/states-schema');
const citiesSchemaModel = require('../models/cities-schema');
const examSchemaModel = require('../models/exam-schema');
const examConfigModel = require('../models/exam-config-schema');
const examRegisterModel = require('../models/regrequests-schema');
const db = require('../config/db');
const bcrypt = require('bcryptjs');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
var jwt = require('jsonwebtoken');
mongoose.Promise = global.Promise;
mongoose.connect(db.database,(err)=>{
if(err){
res.json(err);
}else{
console.log('connected');
}
});
//Register exam
router.post('/exam/register',(req, res)=>{
examConfigModel.findOne({
examcode: req.body.exam
},function(err, result) {
if (err) {
throw err;
} else {
console.log("Rem Seats: " + result.remaining);
if(result.remaining > 0){
console.log("remaining: "+result.remaining);
const examModel = new examRegisterModel();
examModel.userid = req.body.userid;
examModel.stateid = req.body.stateid;
examModel.cityid = req.body.cityid;
examModel.exam_code = req.body.exam;
examModel.father_name = req.body.father_name;
examModel.last_name = req.body.last_name;
examModel.mobileno = req.body.mobileno;
examModel.city = req.body.city;
examModel.street = req.body.street;
examModel.address = req.body.address;
examModel.zipcode = req.body.zipcode;
console.log("RequestBody: "+req.body.exam);
examRegisterModel.findOne({
exam_code: req.body.exam
},function(err, resResult) {
if (err) {
throw err;
} else {
if(resResult == null){
save(examModel,result, res);
}else{
console.log("DB: "+ resResult +" REQ: "+ req.body.exam)
if(resResult.exam_code != req.body.exam){
console.log('notEqual')
save(examModel,result, res);
}else{
console.log()
res.json({reg:'failed',message:"Already Registered",errorCode:"6001"});
}
}
}
});
}else{
res.json({reg:"failed",result:"No seat available",errorCode:7012});
}
}
});
});
function save(examModel,result,res){
examModel.save(function(err,config){
if(err){
console.log(err);
res.json(err);
}else{
console.log(result);
if(result != null){
const reduceCount = result.remaining-1;
res.json({reg:'success',rem:reduceCount,e_id:result._id,errorCode:""});
}
res.json({reg:'success',errorCode:""});
}
});
}
//Update Exam Config
router.put('/update/config/:id',(req, res)=>{
examConfigModel.findByIdAndUpdate(req.params.id,{
$set : {remaining:req.body.rem}
},
{
new : true
},
function(err,updatedExamConfig){
if(err){
console.log(err);
res.json(err);
}else{
res.json({config:'success'});
}
})
});
The reason why you are getting error Can't set headers after they are sent. is because your code has already send back response earlier and trying to send back another response. API has send back response to called, however function has not returned, so function continues till find a return statement or function meets an end that is closing braces.
Example with express.js:
router.post('/your/api', (req, res, next) => {
//Do things here
res.send('Sending response'); // response send
// Doing more things, this is all right
res.send('another response'); // Now error Can't set headers after they are sent.
next();
}, (req, res) => {
res.send('another response'); // Now error Can't set headers after they are sent.
});
res.send() send any kind of response and res.json() send only json response. Use any one again will get error Can't set headers after they are sent.
How to accidentally save from sending multiple response?
Use if-else efficiently.
Use only single res.send / res.json with dynamic statusCode res.status(statusCode).json(result).
Always use return if nothing else is needed to be done once response is send. Example:
```
router.post('/your/api', (req, res, next) => {
//Do things here
return res.send('Sending response'); // response send, and function returned
// Never came here.
// Doing more things, this is all right
return res.send('another response'); // Now error Can't set headers after they are sent.
next();
}, (req, res) => {
// never came here as function already returned.
return res.send('another response'); // Now error Can't set headers after they are sent.
});
```
Related
I am new to this topic of Rest Apis, and I was creating a simple one where I receive a json with movie data and give a small response. As I am new I want to start with what would be the logic and it is an array that is saving data.
But when I send data through PostMan, it saves everything well and does its job, but I get this error on the console.
someone who can guide me please
MY CODE
router.post('/', (req, res) => {
const {titulo, director, year, rating} = req.body;
if (titulo && director && year && rating) {
const id = movies.length + 1;
const newMovie = {...req.body, id};
movies.push(newMovie);
res.json(movies);
} else {
res.status(500).json({error: 'Ha Ocurrido un error'});
}
res.send('recibido');
});
module.exports = router;
CMD ERROR
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at new NodeError (node:internal/errors:371:5)
at ServerResponse.setHeader (node:_http_outgoing:576:11)
at ServerResponse.header (C:\Users\ManuelLeigh\Desktop\restapi\node_modules\express\lib\response.js:776:10)
at ServerResponse.send (C:\Users\ManuelLeigh\Desktop\restapi\node_modules\express\lib\response.js:170:12)
at C:\Users\ManuelLeigh\Desktop\restapi\src\routes\movies.js:20:9
at Layer.handle [as handle_request] (C:\Users\ManuelLeigh\Desktop\restapi\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\ManuelLeigh\Desktop\restapi\node_modules\express\lib\router\route.js:137:13)
at Route.dispatch (C:\Users\ManuelLeigh\Desktop\restapi\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (C:\Users\ManuelLeigh\Desktop\restapi\node_modules\express\lib\router\layer.js:95:5)
at C:\Users\ManuelLeigh\Desktop\restapi\node_modules\express\lib\router\index.js:281:22
Postman Header:
Content-Type: application/json
Your code is trying to send response after it is sent.
Check for following lines, in if and else,, you are already sending response to server and after this is processed, on last line, you are sending some text.
if (titulo && director && year && rating) {
res.json(movies);
} else {
res.status(500).json({error: 'Ha Ocurrido un error'});
}
res.send('recibido');
Update your code as below,
router.post('/', (req, res) => {
const {titulo, director, year, rating} = req.body;
if (titulo && director && year && rating) {
const id = movies.length + 1;
const newMovie = {...req.body, id};
movies.push(newMovie);
res.json(movies);
} else {
res.status(500).json({error: 'Ha Ocurrido un error'});
}
// res.send('recibido');
});
module.exports = router;
after if-else block, you again try to send response.By putting return after sending response in each block, you can fix your problem or other simple way, just comment res.send("recibido").
simple way is to just comment res.send("recibido")
you can write your code this way:
router.post('/', (req, res) => {
const {titulo, director, year, rating} = req.body;
if (titulo && director && year && rating) {
const id = movies.length + 1;
const newMovie = {...req.body, id};
movies.push(newMovie);
res.json(movies);
} else {
res.status(500).json({error: 'Ha Ocurrido un error'});
}
// res.send('recibido');
});
module.exports = router;
Use return statement for res.json, res.status and res.send provided the if else logic is what you want.
I was encountering the above error in my code only to realise wherever I had a logic statement, for some conditions the code kept on running and needed to return the outcome e.g return res.status(400).send("Error Message)
I found the answer to my error by putting a return, but I don't know how correct this solution is
const isAdmin = async (req, res, next) => {
if (req.isAuthenticated() && req.user.role === "admin") {
return next()
} else {
req.flash("danger", "not allowed")
res.redirect("/")
}
return next()
}
I'm using API coded in NodeJS but always Postman identify HttpStatus 200, even when i send 4XX or other.
I'm using express and body-parser
As you can see below:
The code is:
router.get('/', async(req, res) => {
try{
let dados = await busca(0);
let pasta = '/upload/'
let nomearquivo = '';
var contents = '';
if (dados){
for (const [idx,row] of dados.entries()){
nomearquivo = pasta + row.arquivotitulo;
if (fs.existsSync(nomearquivo)){
contents = fs.readFileSync(nomearquivo, {encoding:'base64'});
dados[idx]['arquivotitulo64'] = contents;
}
}
return res.status(200).send(dados);
}else{
return res.sendStatus(404);
}
}catch (err){
console.log(err);
return res.sendStatus(500);
}
});
Can anyone help me to send correctly resposes that turns possible to identify in Postman the correct Status code?
Try like this res.status(404).send('Not Found'); It should work and straightforwrd
I have a NODE.JS api using expressjs that connects to an SQL Server, and I want to use it in an angular project. I make use two files, a route file and a controllers file. My route file is as follows:
module.exports = (app) => {
const UsrContrllr = require('../Controllers/users.controllers');
//1. GET ALL USERS
app.get('/api/users', UsrContrllr.func1);
//2. POST NEW USER
app.post('/api/user/new', UsrContrllr.func2);
};
And my controllers file is given below:
const mssql = require('mssql');
exports.func1 = (req, res) =>
{
// Validate request
console.log(`Fetching RESPONSE`);
// create Request object
var request = new mssql.Request();
// query to the database and get the records
const queryStr = `SELECT * FROM USERS`;
request.query(queryStr, function (err, recordset) {
if (err) console.log(err)
else {
if (recordset.recordset.toString() === '') {
res.send('Oops!!! Required data not found...');
}
else {
// send records as a response
res.send(recordset);
}
};
});
};
exports.func2 = (req, res) =>
{
// Validate request
console.log(`INSERTING RECORD ${req}`);
// create Request object
var request = new mssql.Request();
// query to the database and get the records
const queryStr = `INSERT INTO GDUSERS (USERCODE, PASSWORD, LANGUAGE, USERCLASS, FIRSTNAME, LASTNAME, CONTACTNO) VALUES ('${req.body.usercode}', '${req.body.password}', 'EN', '0', '${req.body.firstname}', '${req.body.lastname}', '${req.body.contactno}');`;
request.query(queryStr, function (err, recordset) {
if (err) console.log(err)
else {
if (recordset.recordset.toString() == '') {
res.send('Oops!!! Required data not found...');
}
else {
// Send records as response
res.send(recordset);
}
};
});
};
The GET request works well, but when I try to run the POST request directly from the angular application, I get an error stating
Cannot GET URL/api/user/new
The angular code in my angular project is:
signup() {
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
console.log(this.user); //User details come from a form
this.http.post(“URL", this.user, options)
.subscribe(
(err) => {
if(err) console.log(err);
console.log("Success");
});
}
I’m not sure whether the angular code I’m using, is right or not, and I don’t know where I’m going wrong. How does one exactly send a http POST request from an Angular project?
this i the way i handled my user signup with http.post calls. my approach is slightly different when signing up user because i am using a promise instead of observable (which i normally use for my servicecalls). but i will show you both ways.
createUser(user: User): Promise < string > {
const promise = new Promise < string > ((resolve, reject) => {
const userForPost = this.createUserForPost(user);
this.http.post(environment.backendUrl + '/api/user/signup', userForPost, this.config).toPromise < HttpConfig > ()
.then(createdUser => {
}).catch(error => {
console.log(error);
});
});
return promise;
}
here another example with an observable
createForumPost(forumPost: ForumPost) {
this.http.post < { message: string, forumPostId: string } > (environment.backendUrl + '/api/forumPosts', forumPost).subscribe((responseData) => {
const id = responseData.forumPostId;
forumPost.id = id;
});
}
i defined my URL somewhere else and then just use the environment.backedUrl + 'path' to define my path (the same as the path in your backend controller)
this is one of my first answers here on SO. i am sry if it is a bit messy
i hope i was able to help with my examples :)
The line res.send("Successfully saved the new address."); throws the
'ERR_HTTP_HEADERS_SENT' error.
I read through other posts concerning the same error and tried return res.send("Successfully saved the new address."), but that doesn't fix it. Any insights?
Note: I am new to this.
Please be kind.
Thanks.
My Code
app.post("/", function(req, res) {
const url = "http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/findAddressCandidates?";
const street = req.body.street;
const city = req.body.city;
const state = req.body.state;
const zip = req.body.zip;
const yourAddress = "Address=" + street.replace(" ", "+") + "&City=" + city.replace(" ", "+") + "&Zip=" + zip;
const parameters = "&category=&outFields=*&forStorage=false&f=json";
request(url + yourAddress + parameters, function(error, response, body) {
const data = JSON.parse(body);
const newAddress = data.candidates[0].address;
const longitude = data.candidates[0].location.x;
const latitude = data.candidates[0].location.y;
const address = new Address({
address: newAddress,
latitude: latitude,
longitude: longitude
});
address.save(function(err) {
if (!err) {
res.send("Successfully saved the new address.");
} else {
res.send(err);
}
});
});
res.redirect("/");
});
You are doing both res.send() and res.redirect() in the same request handler. You can't send two responses to the same request. That's what generates the warning message you see.
Pick one of the other. You either want to send an appropriate status about the .save() or you want to redirect. One or the other, not both.
In this particular code, the res.redirect() happens first so it's what the client sees. Then, after that and when the request() and the address.save() have both completed, then you try to res.send(), but that is blocked because a response has already been sent and the http connection is already done.
If you just want to redirect upon successful save, you can remove the existing res.redirect() and change to this:
address.save(function(err) {
if (!err) {
res.redirect("/");
} else {
console.log(err);
res.sendStatus(500);
}
I would Agree With #jfriend00 answer , since there can be only one response for the request .
Here's what you can do:
address.save(function(err) {
if (!err) {
res.redirect('/success')
} else {
res.send(err);
}
});
//add a new route
app.get('/success',(req,res)=>{res.send('Successfully saved the new address.')})
And then you can redirect to the home page.
This is just a workaround in this case and can differ logically in each case depending on the requirement
The Other Way is to redirect on the client side itself
eg:If you're on jquery
$.ajax({
statusCode: {
200: function() {
$(location).attr('href', 'to the homepage')
}
}
});
I have the following code to insert data into DB - this code has to be executed in a sequential order
Router JS
module.exports = function(app) {
app.get('/registerUser', function(req, res ) {
objuser.userName = 'testuser';
objuser.password = 'password';
objuser.status = true;
registerUser (objuser ); //calls Business.js
res.OK();
res.end ();
});
}
Business.js
var registerUser = function (objuser )
{
userDB.registerUser (objuser ) ; //calls db.js
};
db.js
exports.registerUser = function (objUser )
{
var User = db.model(strCollectionName, UserSchema );
var objSchema = new User(objUser);
objSchema.save(function (err)
{
if (err)
console.error (err);
else
console.log ("registerUser : Data insertion success.");
});
}
In the db.js Im getting error from Mongo if I try to insert duplicate value. I wan to pass the error message to HTML page to display the same. What should I do? I tried
throw Error (err)
But it breaks the server.
Assuming you are using expressjs, I'd make use of the next callback. like so:
app.get('/registerUser', function (req, res, next) {
objuser.userName = 'testuser';
objuser.password = 'password';
objuser.status = true;
registerUser(objuser, function (err) {
if(err) {
//this will be handled by express's errorHandler or whatever you have configured
return next(err);
}
//do whatever you want to do with the response
});
});
If you don't want to make your Business.js call async then you will obviously change this code to a try...catch flow. Node.js apps are happier using async calls though, so a common convention in nodejs apps is to expose a callback using the (err, result) parameters. So your db.js call would be :
exports.registerUser = function (objUser, callback )
{
var User = db.model(strCollectionName, UserSchema );
var objSchema = new User(objUser);
objSchema.save(function (err) {
if (err) return callback(err);
return callback(null, objSchema);
});
}
By now you probably notice that your Business.js call would just be a mediator between your route and your db code...whether you need it or not is up to you.
HTH,
Mike
If you are using node.js >= 0.8.x you can use connect-domain middleware that adds new domain functionality to your express/connect application. With doamin module you don't need to pass error up manually. You can simple throw error and it will be passed to error handler automatically.