var _expressPackage = require("express");
var _bodyParserPackage = require("body-parser");
var _sqlPackage = require("mssql");
//Initilize app with express web framework
var app = _expressPackage();
//To parse result in json format
app.use(_bodyParserPackage.json());
***//Here we will enable CORS, so that we can access api on cross domain.***
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, contentType,Content-
Type,
Accept, Authorization");
next();
});
***//Lets set up our local server now.***
var server = app.listen(process.env.PORT || 4000, function () {
var port = server.address().port;
console.log("App now running on port", port);
});
***//Set up your sql connection string, i am using here my own, you have to replace it with your
own.***
var dbConfig = {
user: "sa1",
password: "12345",
server: "localhost",
database: "test123"
};
***//Function to connect to database and execute query***
var QueryToExecuteInDatabase = function (response, strQuery) {
***//close sql connection before creating an connection otherwise you will get an error if
connection already exists.***
_sqlPackage.close();
//Now connect your sql connection
_sqlPackage.connect(dbConfig, function (error) {
if (error) {
console.log("Error while connecting to database :- " + error);
response.send(error);
}
else {
***//let's create a request for sql object***
var request = new _sqlPackage.Request();
//Query to run in our database
request.query(strQuery, function (error, responseResult) {
if (error) {
console.log("Error while connecting to database:- " + error);
response.send(error);
}
else {
response.send(responseResult);
}
});
}
});
}
***//GET API***
app.get("/StudentList", function(_req ,_res){
var Sqlquery = "select * from student1"; ***//tbl_studentdetails***
QueryToExecuteInDatabase(_res, Sqlquery);
});
***//call a stored procedure***
var request = new _sqlPackage.Request();
***//calling a stored procedure***
request.input('Username', _sqlPackage.VarChar(50), 'admin');
request.input('Password', _sqlPackage.VarChar(50), 'admin#123');
request.execute('sp_CheckLogin', function (err, recordsets, returnValue) {
response.send(recordsets);
});
> (D:\performalytic\9999.practice\angularpra\NodeApiWithSql\node_modules\mssql\lib\tedious\request.js:701:23)
at processImmediate (internal/timers.js:463:21)
- end snippet -->
This question could use a bit more clarity... but with the limited information provided it appears the issue you are running into here has to do with lexical scope.
Lexical scope most simply has to do with what variables the current execution context has access to. Inside of a function, you can either access variables declared within the function... or in the surrounding code. The last line of your code snipped shows a top level variable request and a method on that object called execute.
The callback you are passing the execute method has three variables (function parameters) you're naming err, recordsets, and returnValue. Yet inside that function body you're attempting to access a variable named response. If we look in the surrounding code... there is no response variable declared. (The only variable named response I see is within the QueryToExecuteInDatabase, and therefore only accessible within that function body.
Where are you getting this templated code from?
Related
I have a firebase function called sendMail that is used to send emails. I am trying to pass the email address of the receiver and another parameter to the function. In my vue app I call the function as follows:
sendEmail(){
console.log(this.email)
let sendMail = firebase.functions().httpsCallable('sendMail');
sendMail(
{
"email": this.email,
"superu": this.superu
}
).then(
result => {
console.log(result)
}
)
}
And my function index.js looks like:
const functions = require('firebase-functions');
const admin = require("firebase-admin")
const nodemailer = require('nodemailer');
admin.initializeApp()
//google account credentials used to send email
var transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth: {
user: '*****#****.com',
pass: '***********'
}
});
exports.sendMail = functions.https.onRequest((req, res) => {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Content-Type");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
console.log(req.body['data']);
const mailOptions = {
from: `•••••••••#gmail.com`,
to: req.body['data'].email,
subject: 'contact form message',
html: `<h2 style="color: teal">Order Confirmation</h2>
<a href="https://track-acquintances.firebaseapp.com/signup/${req.body.superu}">
<b> Register </b>"<br>
</a>`
};
return transporter.sendMail(mailOptions, (error, data) => {
if (error) {
return res.status(200).json({data: error.message});
}
data = JSON.stringify(data)
return res.status(200).json({data: data});
});
});
The problem is I can't access the passed email data and the function fails. I logged req.body['data'] to the functions logs and I see { email: 'xxx#xx.xxx.x', superu: true }. But I tried both req.body['data'].email and req.body['data']['email'] and they both doesn't work. And in my browsers console I get {data: "No recipients defined"}. Any help would be appreciated. Thank you
You're confusing two types of Cloud Functions:
Your Cloud Function is defined as an HTTPS triggered function, which means that you can invoke it by accessing its URL in a browser, by calling fetch, or by using XMLHTTPRequest.
Your client code, tries to invoke a so-called Callable Cloud Function, which is a different type. While Callable Cloud Functions are also invoked directly over HTTPS, they have a specific wire protocol for being invoked.
Since the two types of function don't match, your client code is passing the parameters in a different format than what the server is handling.
You'll need to either call the HTTPS function, or convert the Cloud Function to be Callable. The latter would look something like:
exports.sendMail = functions.https.onCall((data, context) => {
const email = data.email;
const superu = data.superu;
...
});
I'm trying to save a variable to a text file, but if the variable isn't found when using spotifyApi.clientCredentialsGrant(), then I want my server to redirect to app.get('/error', function(req, res) {}); which displays a different webpage, but it's returning the error:
(node:11484) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
How can I get around this error to display the webpage error.html?
I don't have access to EJS or window.location because it conflicts with other files and it's a node.js program, respectively.
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, '/public', 'homepage.html'));
try {
spotifyApi.clientCredentialsGrant()
.then(function (data) {
// Save the access token so that it's used in future calls
client_cred_access_token = data.body['access_token'];
console.log(client_cred_access_token);
console.log('Client Credentials Success!');
}, function (err) {
console.log('Something went wrong when retrieving an access token', err.message);
throw err;
});
fs.writeFile("./public/client_cred_token.txt", '', function (err) {
console.log('Clearing previous access token');
});
fs.writeFile("./public/client_cred_token.txt", client_cred_access_token, function (err) {
if (err) return console.log(err);
});
fs.readFile('./public/client_cred_token.txt', function (err, data) {
if (err) throw err;
console.log("Saved Client Credentials as: %s", data)
});
}
catch (err) {
res.redirect('/error');
}
});
Key takeaway from the accepted answer is to not send any HTML/files to the server until it's confirmed which one is needed.
You are calling res.sendFile() first and then if you later get an error, you are also calling res.redirect('/error') which means you'll be trying to send two responses to one http request which triggers the error you see. You can't do that.
The solution is to call res.sendFile() at the end of all your other operations so you can then call it when successful and call res.redirect() when there's an error and thus only call one or the other.
In a difference from the other answer here, I've shown you how to code this properly using asynchronous file I/O so the design could be used in a real server designed to serve the needs of more than one user.
const fsp = require('fs').promises;
app.get('/', async function (req, res) {
try {
let data = await spotifyApi.clientCredentialsGrant();
// Save the access token so that it's used in future calls
client_cred_access_token = data.body['access_token'];
console.log(client_cred_access_token);
console.log('Client Credentials Success!');
await fsp.writeFile("./public/client_cred_token.txt", client_cred_access_token);
let writtenData = await fsp.readFile('./public/client_cred_token.txt');
console.log("Saved Client Credentials as: %s", writtenData);
res.sendFile(path.join(__dirname, '/public', 'homepage.html'));
} catch (err) {
console.log(err);
res.redirect('/error');
}
});
app.get('/', function (req, res) {
try {
spotifyApi.clientCredentialsGrant().then(function (data) {
// Save the access token so that it's used in future calls
let client_cred_access_token = data.body['access_token'];
console.log(client_cred_access_token);
console.log('Client Credentials Success!');
// truncate token file
fs.truncateSync("./public/client_cred_token.txt");
// write token to file
fs.writeFileSync("./public/client_cred_token.txt", client_cred_access_token);
// read token from file again
// NOTE: you could use `client_cred_access_token` here
let data = fs.readFileSync('./public/client_cred_token.txt');
console.log("Saved Client Credentials as: %s", data)
// send homepage to client when no error is thrown
res.sendFile(path.join(__dirname, '/public', 'homepage.html'));
}, function (err) {
console.log('Something went wrong when retrieving an access token', err.message);
throw err;
});
} catch (err) {
res.redirect('/error');
}
});
I swapped all asynchron file opreations with the syncron one.
They throw an error and you dont have to deal with callback chain/flow.
Also i moved the sendFile(...) at the botom in the try block, so when a error is thrown from any syncrhonus function call the sendFile is not reached, and your redirect can be sent to the client.
Otherwise you would send the homepage.html to the client, with all headers, and a redirect is not possible.
I'm having a strange Can't set headers after they are sent crash on my NodeJs/Express app.
The crashing request : POST /auth/form
How the request is server-side handled
app.js
[...]
var auth_route = require('./routes/auth');
app.use('/auth', auth_route );
[...]
auth.js
var AuthController = require('../controller/auth_controller');
[...]
router.post("/form", function(req, res) {
[...]
auth_ctrl.form_login(username, password);
});
auth_controller.js
AuthController.prototype.form_login = function(username, password) {
_this.user_model.get_by_username(username, function(user) {
if (user == null)
return (Response.send_204(_this.res, "User not found"))
password.isTheSame(password, user.password, function(err, res) {
if (err)
return (Response.send_error_response(_this.res, 500, "Internal server error occured, sorry about that.."));
if (!res)
return (Response.send_error_response(_this.res, 401, "Wrong password"));
// Crash seems to happen on the above 401 response which is the 67th lines of my auth_controller file (cf. callstack bellow)
_this.start_user_session(user, function(err) {
if (err)
return (Response.send_error_response(_this.res, 500, "Internal server error"));
return (Response.send_200(_this.res, "You are logged!"));
})
});
})
}
Response.send_error_response source code if needed
function send_error_response(res, code, message, missing_fields) {
[..]
res.header('Content-Type', 'application/json')
res.status(code).send(JSON.stringify({
[..]
}));
}
The callstack trace
POST /auth/form 401 2.408 ms - -
_http_outgoing.js:356
throw new Error('Can\'t set headers after they are sent.');
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:356:11)
at ServerResponse.header (C:\Users\ME\dev\app\node_modules\express\lib\response.js:719:10)
at Object.send_error_response (C:\Users\ME\dev\app\core\lib\Response.Library.js:30:6)
at C:\Users\ME\dev\app\controller\auth_controller.js:67:22
How I make this crash happen
I keep pushing down my enter button which send a looot of requests from the same origin.
It seems that's happening inside password callback function...
Any suggestions ? Thanks in advance !
My guess is that your implementation of AuthController does something like this:
var _this;
function AuthController(req, res) {
this.req = req;
this.res = res;
_this = this;
}
This "promotes" _this to a (module-wide) global, which gets overwritten for every request that posts to /auth/form. If two of those requests are sent in quick succession, you could end up with the situation that a response is send using the same _this more than once, which would result in the error that you got:
request 1 comes in, _this points to its controller instance
request 2 comes in, _this gets overwritten to point to its controller instance
request 1 is done and sends back a response, using the _this that belongs to request 2
request 2 is done and sends back a response, using the same _this, resulting in an error
So, don't use globals, use this instead:
AuthController.prototype.form_login = function(username, password) {
this.user_model.get_by_username(username, function(user) {
...
});
};
You can always create a function-scoped variable to hold a reference to it, if preferable:
AuthController.prototype.form_login = function(username, password) {
var _this = this;
_this.user_model.get_by_username(username, function(user) {
...
});
};
I have some http-server which is wrapped by domain-module.
Server send error on some request. Is there any approach to get request object which provoked error?
var http = require('http');
var domain = require('domain');
var d = domain.create();
d.on('error', function(err) {
console.error("Sorry, dude, we have a problem");
console.error(err.stack);
});
d.run(function() {
http.createServer(function(req, res) {
someBadFunction();
res.end();
}).listen(8080);
}
);
You can add the request to the domain, and filter it out in the error handler:
d.on('error', function(err) {
var req = d.members.filter(function(member) {
return member instanceof http.IncomingMessage;
})[0];
d.remove(req);
...
});
d.run(function() {
http.createServer(function(req, res) {
d.add(req);
someBadFunction();
res.end();
}).listen(8080);
});
However, if I were to use domains (they are being deprecated), I would create a new domain for each request (as per this documentation) instead of adding each request to the top-level domain, as I don't think the code above will work properly with any reasonable amount of requests coming in.
I am new to loopback and node.js.
I have created two models: Rating and RatingsAggregate
using the loopback explorer, I can query and post against the API just fine.
I am try to setup some basic business logic so I am editing the file Rating.js in common/models
Here is the content of it:
module.exports = function(Rating) {
Rating.afterRemote('**', function(ctx, inst, next) {
var loopback = require('loopback');
var app = loopback();
var ratingsaggregate = app.models.ratingsaggregate;
ratingsaggregate.post({"source":"foobar","restaurantID":"foobar","itemMenuName":"foobar","itemSectionName":"foobar","itemName":"foobar","nRatings1":123,"nRatings2":123,"nRatings3":123,"nRatings4":123,"nRatings5":123,"hasImage":true,"imageSize":123,"latestImageRatingID":"foobar","imageCount":123,"lastUpdated":"foobar"}, function(err, response) {
if (err) console.error(err);
next();
});
});
};
I can load my API, but whenever I run a get statement against it, I get this error:
TypeError: Cannot call method 'post' of undefined
My guess is that somehow ratingsaggregate never gets a value... but I don't know what I am doing wrong. Obviously this is not the end state of my business logic, but I am trying some basic CRUD right now between two models
And... here is the answer. There was a getModel function hidden in the documentation
module.exports = function(Rating) {
Rating.afterRemote('create', function(ctx, inst, next) {
var loopback = require('loopback');
var ratingsaggregate = loopback.getModel('ratingsaggregate');
ratingsaggregate.create({"source":"foobar","restaurantID":"foobar","itemMenuName":"foobar","itemSectionName":"foobar","itemName":"foobar","nRatings1":123,"nRatings2":123,"nRatings3":123,"nRatings4":123,"nRatings5":123,"hasImage":true,"imageSize":123,"latestImageRatingID":"foobar","imageCount":123,"lastUpdated":"foobar"}, function(err, response) {
if (err) console.error(err);
next();
});
});
};
Fixes everything and the behaviour is the expected one