Cannot set Header after already being sent // node express - express

I am prompted with cannot set headers after they are already being set.
My code intercept for put method sent on the URL it then checks for missing id, after that checks if no field inputted is undefined it then perform try-catch method within which it updates for given id. If the id is not correct then it responds with an error.
My code is :
.put(async function (req, res){
console.log(req.body._id + " is id.")
const {_id, issue_title, issue_text, created_by, assigned_to, status_text, open} = req.body;
if(!_id){
res.json({error: "missing _id"})
}
const fields = {issue_title, issue_text, created_by, assigned_to, status_text, open}
const checkAllUndefined = Object.values(fields).every(val => (val == undefined || val == '')? true: false)
if(checkAllUndefined){
res.json({ error: 'no update field(s) sent', _id})
} else{
try{
await db.findOneAndUpdate({_id: new mongodb.ObjectID(_id)}, {$set:
{issue_title,issue_text,created_by, assigned_to, status_text, open,
updated_on: new Date()}}, {
new: true,
omitUndefined: true
})
res.json({ result: 'successfully updated', _id})
}catch(err){
res.json({ error: 'could not update', _id})
}
}
})

Your first If statement is returning the response if _id is undefined !
if(!_id){
res.json({error: "missing _id"})
}
After sending this response your next if block or its else block gets executed
which leads to sending another response which is not possible or allowed !, You have to nest if else block like this
put(async function (req, res) {
console.log(req.body._id + " is id.")
const {_id, issue_title, issue_text, created_by, assigned_to, status_text, open} = req.body;
if (!_id) {
res.json({error: "missing _id"})
} else {
if (checkAllUndefined) {
res.json({error: 'no update field(s) sent', _id})
} else {
try {
await db.findOneAndUpdate({_id: new mongodb.ObjectID(_id)}, {
$set:
{
issue_title, issue_text, created_by, assigned_to, status_text, open,
updated_on: new Date()
}
}, {
new: true,
omitUndefined: true
})
res.json({result: 'successfully updated', _id})
} catch (err) {
res.json({error: 'could not update', _id})
}
}
}
)
}
by doing this you are only sending response only once.

Related

Syntax required for conditional variable use to modify SQL query in Node.JS

I've fairly new to NodeJS, and I'm not sure of the best method or syntax to create an MS SQL query with conditional code. Here's what I want to do, with the query greatly simplified, and using some pseudocode:
// #route GET /api/flow/data/references
async function getDataReferences(req, res) {
const { station, type } = req.query
let pool
try {
pool = await sql.connect(config)
const { recordset } = await pool
.request()
.input('station', sql.NVarChar(50), station).query`
SELECT Reference
FROM TABLE
WHERE Status = 'Done' ` +
if(type === 1) {
`AND Station_1 = #station`
} else if(type === 2) {
`AND Station_2 = #station`
} else {
`AND Station_3 = #station`
}
+ `AND Process = 5`
const processedData = recordset.map((item) => item.Reference)
res.json(processedData)
} catch (error) {
console.log(
`ERROR with Station: ${station} with Type: ${type}`,
error.message,
new Date()
)
res.status(500).json({ message: error.message })
} finally {
await pool.close()
}
}
Depending on the value of "type" supplied to the function, I want the query to reference a different DB column.
UPDATE:
So I've found that the following works, although arguably the formatting isn't quite as nice.
// #route GET /api/flow/data/references
async function getDataReferences(req, res) {
const { station, type } = req.query
let station_column
if(type === 1) {
station_column = 'AND Station_1 = #station'
} else if(type === 2) {
station_column = 'AND Station_2 = #station'
} else {
station_column = 'AND Station_3 = #station'
}
let query = `
SELECT Reference
FROM TABLE
WHERE Status = 'Done'
${station_column}
AND Process = 5`
let pool
try {
pool = await sql.connect(config)
const { recordset } = await pool
.request()
.input('station', sql.NVarChar(50), station).query(query)
const processedData = recordset.map((item) => item.Reference)
res.json(processedData)
} catch (error) {
console.log(
`ERROR with Station: ${station} with Type: ${type}`,
error.message,
new Date()
)
res.status(500).json({ message: error.message })
} finally {
await pool.close()
}
}
I tried just using the template literal substitutions directly in the query, but that wouldn't work. (Perhaps for reasons stated here: https://github.com/tediousjs/node-mssql#es6-tagged-template-literals )
If I don't get any better answer, I'll post this as the answer; but would like to know if there's a best practice method for doing this.
Seems like this works, and isn't overly complicated:
// #route GET /api/flow/data/references
async function getDataReferences(req, res) {
const { station, type } = req.query
let station_column
if(type === 1) {
station_column = 'AND Station_1 = #station'
} else if(type === 2) {
station_column = 'AND Station_2 = #station'
} else {
station_column = 'AND Station_3 = #station'
}
let query = `
SELECT Reference
FROM TABLE
WHERE Status = 'Done'
${station_column}
AND Process = 5`
let pool
try {
pool = await sql.connect(config)
const { recordset } = await pool
.request()
.input('station', sql.NVarChar(50), station).query(query)
const processedData = recordset.map((item) => item.Reference)
res.json(processedData)
} catch (error) {
console.log(
`ERROR with Station: ${station} with Type: ${type}`,
error.message,
new Date()
)
res.status(500).json({ message: error.message })
} finally {
await pool.close()
}
}
Essentially, create the full query string in advance, including the parameters to bind, and then pull that whole string in as the query.

I am trying to use prepared statements to insert values given in an array

I am trying to INSERT values given in an array into my table, where each element of the array is a column in the table. Keep in mind this is for an API so the data is received through requests.
Here's the concerned parts in my code:
user.model.js:
User.create = function (newUser, result) {
console.log(Object.values(newUser));
dbConn.query("INSERT INTO user(user_fname, user_name, user_email, user_phone, user_is_admin) set ?", Object.values(newUser), function (err, res) {
if (err) {
console.log("error: ", err);
result(err, null);
} else {
console.log(res.insertId);
result(null, res.insertId);
}
});};
user.controller.js:
exports.create = function (req, res) {
const new_user = new User(req.body);
console.log(req.body);
if (req.body.constructor === Object && Object.keys(req.body).length === 0) {
res.status(400).send({
error: true,
message: 'Please provide all required field'
});
} else {
console.log(new_user);
User.create(new_user, function (err, user) {
if (err) {
res.send(err);
}
res.json({
error: false,
message: "User added successfully!",
data: user
});
});
}};
In this last bit of code here is the output of the console.logs:
{
user_fname: 'toto',
user_name: 'titi',
user_email: 'who#where.how',
user_phone: '1010101010',
user_is_admin: 'false'
}
User {
fname: 'toto',
name: 'titi',
email: 'who#where.how',
phone: '1010101010',
is_admin: 'false'
}
[ 'toto', 'titi', 'who#where.how', '1010101010', 'false' ]
And last but not least here's the error message I get:
error: SqlError: (conn=357, no: 1064, SQLState: 42000) You have an
error in your SQL syntax; check the manual that corresponds to your
MariaDB server version for the right syntax to use near 'set 'toto''
at line 1 sql: INSERT INTO user(user_fname, user_name, user_email,
user_phone, user_is_admin) set ? -
parameters:['toto','titi','who#where.how','1010101010','false']
I'm clear on the fact my syntax is wrong but I can't seem to find anything that works. Thank you for your time :)
Found the answer !
So as I thought my syntax was wrong, here's the correct way to do it:
User.create = function (newUser, result) {
console.log(Object.values(newUser));
dbConn.query("INSERT INTO user(user_fname, user_name, user_email, user_phone, user_is_admin) values(? , ? , ? , ? , ?)", Object.values(newUser), function (err, res) {
if (err) {
console.log("error: ", err);
result(err, null);
} else {
console.log(res.insertId);
result(null, res.insertId);
}
});
};

getting blank array when consoled logged out results in nodejs mysql

I have this code where I want to check for existing email but I am not able to get the array of all the data containing matched row by SQL.
var email = req.body.email;
var fullname = req.body.fullname;
var userPassword = req.body.userPassword
const saltRounds = 10
let sql = 'SELECT * FROM registeredusers WHERE id = ?'
pool.query(sql, email, (err, results) => {
console.log(JSON.stringify(results))
if (err) {
return res.status(500).json({
message: 'Internal server error. Retry... '
})
}
else if (results === 1) {
return res.status(500).json({
message: 'Email already exist.',
res: results
})
}
just use
let sql = 'SELECT COUNT(*) AS cnt FROM registeredusers WHERE email = ?'
pool.query(sql, [req.body.email], (err, results) => {
if (err) {
return res.status(500).json({
message: 'Internal server error. Retry... '
})
}
else if (results[0].cnt > 0) {
return res.status(500).json({
message: 'Email already exist.',
})
}

TypeError: response.data is undefined

I'm having problems with promise response for a vForm PUT to UPDATE a model (backend in laravel).
The response code is 200 (OK, updated) and the model is updated, but I don't know why I'm having error with "response.data" in catch. There is no error and code in ".then()" is running correctly.
EDIT
Service Update funciton (vue) using vForm.
updateService(){
this.$Progress.start();
this.service.put('api/service/' + this.service.id)
.then( function (response) {
Toast.fire({
type: 'success',
title: response.data['Response']
});
this.$Progress.finish();
})
.catch( function (response) {
console.log(response);
Swal.fire("Error!", response.data['Response'], "warning");
this.$Progress.fail();
});
this.$events.$emit('ServiceInform');
},
Function in backend (laravel).
public function update(Request $request, Service $service)
{
$this->validate($request, [
'id_customers' => 'required|int',
'date' => 'required|date',
'id_technicians' => 'required|int',
'location' => 'required|string',
'details' => 'required|string'
]);
if ($request['id_technicians'] !== $service['id_technicians']) {
$assignated_by = Auth::user()->id;
$assigned_date = date('Y-m-d H:i:s');
} else {
$assignated_by = $service['assignated_by'];
$assigned_date = $service['assigned_date'];
}
if ($request['id_technicians'] == 0) {
$state = 'P';
} else {
$state = 'I';
}
$service->date = $request['date'];
$service->id_technicians = $request['id_technicians'];
$service->location = $request['location'];
$service->details = $request['details'];
$service->assigned_date = $assigned_date;
$service->assigned_by = $assignated_by;
$service->state = $state;
try {
$service->save();
return Response::json([
'Response' => 'Servicio actualizado.'
], 201);
} catch (Exception $e) {
return Response::json([
'Response' => 'No se actualizó el servicio.'
], 422);
}
}
This line looks problematic to me:
this.$Progress.finish();
It's trying to access this within the function passed to then. It seems unlikely that this will be referencing what you're expecting. You should be able to confirm with suitable console logging. My suspicion is that attempting to call this.$Progress.finish() will throw an error, triggering the catch.
Try using arrow functions for your then and catch callbacks instead.

sinon stub is not working

I'm quiet new into testing and I don't seem to succeed to succesfully stub a function. I'm trying to stub the connection to the database, but it keep's contacting it, instead of using the result from the stub:
Here's the function:
var self = module.exports = {
VerifyAuthentication: function (data){
var deferred = q.defer()
if(typeof(data.email)=='undefined'){
deferred.reject({data:{},errorcode:"",errormessage:"param 'email' is mandatory in input object"})
}else{
if(typeof(data.password)=='undefined'){
deferred.reject({data:{},errorcode:"",errormessage:"param 'password' is mandatory in input object"})
}else{
var SqlString = "select id, mail, password, origin from tbl_user where mail = ?"
var param = [data.email]
self.ExecuteSingleQuery(SqlString, param).then(function(results){
if(results.length > 0)
{
if (results[0].password == data.password)
{
deferred.resolve({data:{"sessionId":results[0].id},errorcode:"",errormessage:""})
}else{
deferred.reject({data:{},errorcode:"",errormessage:"bad password"})
}
}else{
deferred.reject({data:{},errorcode:"",errormessage:"unknown user"})
}
})
}
}
return deferred.promise
},
ExecuteSingleQuery: function (queryString, parameters){
var deferred = q.defer()
var connection = connect()
connection.query(queryString, parameters, function (error, results, fields){
if(error){ deferred.reject(error)};
deferred.resolve(results)
});
return deferred.promise
},
And here's the test:
var dbconnection = require('../lib/dbConnection.js')
describe("VerifyAuthentication", function(){
it("_Returns DbResult object when user name and password match", function(){
var expectedResult = {data:{"sessionKey":"b12ac0a5-967e-40f3-8c4d-aac0f98328b2"},errorcode:"",errormessage:""}
stub = sinon.stub(dbconnection, 'ExecuteSingleQuery').returns(Promise.resolve(expectedResult))
return dbconnection.VerifyAuthentication({email:"correct#adres.com",password:"gtffr"}).then((result)=>{
expect(result.data.sessionId).to.not.be.undefined
expect(result.errorcode).to.not.be.undefined
expect(result.errormessage).to.not.be.undefined
stub.restore()
})
})
})
I always got an error 'unknown user', which is normal, because the user is indeed not in the database. However, I want to stub the 'ExecuteSingleQuery' function, avoiding it to connect to DB.
I have fixed a couple of issues in your code and posting the corrected files below.
dbConnection.js
var self = module.exports = {
VerifyAuthentication: function (data) {
var deferred = q.defer();
if (typeof (data.email) == 'undefined') {
deferred.reject({
data: {},
errorcode: '',
errormessage: "param 'email' is mandatory in input object"
});
} else {
if (typeof (data.password) == 'undefined') {
deferred.reject({
data: {},
errorcode: '',
errormessage: "param 'password' is mandatory in input object"
});
} else {
var SqlString = 'select id, mail, password, origin from tbl_user where mail = ?';
var param = [data.email];
self.ExecuteSingleQuery(SqlString, param).then(function (results) {
if (results.length > 0) {
if (results[0].password === data.password) {
deferred.resolve({
data: {
'sessionId': results[0].id
},
errorcode: '',
errormessage: ''
});
} else {
deferred.reject({
data: {},
errorcode: '',
errormessage: 'bad password'
});
}
} else {
deferred.reject({
data: {},
errorcode: '',
errormessage: 'unknown user'
});
}
});
}
}
return deferred.promise;
},
ExecuteSingleQuery: function (queryString, parameters) {
var deferred = q.defer();
var connection = connect();
connection.query(queryString, parameters, function (error, results, fields) {
if (error) {
deferred.reject(error);
}
deferred.resolve(results);
});
return deferred.promise;
}
};
dbConnection.test.js
describe('VerifyAuthentication', function () {
it('Returns DbResult object when user name and password match', function () {
var expectedResult = [{
id: '123',
password: 'gtffr'
}];
const stub = sinon.stub(dbconnection, 'ExecuteSingleQuery').resolves(expectedResult);
return dbconnection.VerifyAuthentication({
email: 'correct#adres.com',
password: 'gtffr'
}).then((result) => {
expect(result.data.sessionId).to.not.be.undefined;
expect(result.errorcode).to.not.be.undefined;
expect(result.errormessage).to.not.be.undefined;
stub.restore();
});
});
});
I am outlining the problematic parts below:
The expectedResult variable had a wrong type of value. In the
self.ExecuteSingleQuery() implementation you check for an array with length > 0. The fixed result returned by the stub, was an object instead of an array and this is why it returned the unknown user exception
The array should contain an object with { id: 'xxx', password: 'gtffr' } attributes. Password is validated against the one used by the dbconnection.VerifyAuthentication({email:"correct#adres.com",password:"gtffr"}) call
Finally, I have changed the stub statement to resolve instead of return as shown here const stub = sinon.stub(dbconnection, 'ExecuteSingleQuery').resolves(expectedResult); - this is the preferred method of resolving a promise