I'm new to NodeJS, and JS in general (mostly a PHP and C# guy), so I could really use some help with this function below.
The goal is to receive a JSON payload, connect to MySQL, and then return the results of the query in a JSON response. I've got it connecting to the DB, I can read the JSON data that it receives (event.fieldname) but for some reason it's not sending back the JSON for the applicant_data variable.
Do I just have the variable in the wrong location? When I run the code below I just get back "{}" as the returned data.
Thanks in advance for the help!
NodeJS Code:
exports.handler = function(event, context, callback) {
console.log('Starting:');
console.log("Request received:\n", JSON.stringify(event));
var mysql = require('mysql');
var jsonconnection = mysql.createConnection({
host: 'servername',
user: 'username',
password: 'password',
database: 'database'
});
jsonconnection.connect();
console.log('Connected to MySQL:');
jsonconnection.query('SELECT applicant_id FROM customers WHERE applicant_id = \'' + event.applicant_id + '\'',
function(err,res){
if(err) throw err;
console.log('Row Details:', JSON.stringify(res));
var applicant_data = {
applicant_id : res.applicant_id
};
jsonconnection.end();
context.succeed(applicant_data);
})
};
I am not familiar with AWS, but base on http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html, following code may work.
exports.handler = function (event, context, callback) {
console.log('Starting:');
console.log("Request received:\n", JSON.stringify(event));
var mysql = require('mysql');
var jsonconnection = mysql.createConnection({
host: 'servername',
user: 'username',
password: 'password',
database: 'database'
});
// Move applicant_data outside of query as it will be needed at the end in callback
var applicant_data = {};
jsonconnection.connect();
console.log('Connected to MySQL:');
jsonconnection.query('SELECT applicant_id FROM customers WHERE applicant_id = \'' + event.applicant_id + '\'',
function (err, res) {
if (err) throw err;
console.log('Row Details:', JSON.stringify(res));
applicant_data = {
// Only use first row of data
applicant_id: res[0].applicant_id;
};
});
// Move connection end out side of query
jsonconnection.end();
// This should return your data, in JSON form
callback(null, JSON.stringify(applicant_data));
// I assume this is the correct use for succeed
context.succeed();
};
exports.handler = async (event) => {
let jsonResponse = {"hello":"world"}
const response = {
statusCode: 200,
body: JSON.stringify(jsonResponse),
};
return response;
};
Related
Im using Tedious in Node JS to return a simple SQL Query :
var Connection = require('tedious').Connection;
var config = {
server: 'myserver.database.windows.net',
authentication: {
type: 'default',
options: {
userName: 'myusername',
password: 'mypassword',
rowCollectionOnDone: true,
rowCollectionOnRequestCompletion: true
}
},
options: {
encrypt: true,
database: 'mydatabase'
}
};
const connection = new Connection(config);
connection.on('connect', function(err) {
if (err) {
console.log(err);
}else{
console.log("Connected");
}
});
var Request = require('tedious').Request
var TYPES = require('tedious').TYPES;
let results = [];
function checkId(cid) {
request = new Request("SELECT * FROM mytable WHERE id = #cid",function(err, rowCount, rows) {
if (err) {
console.log(err);
}
});
request.addParameter('cid', TYPES.NVarChar, cid);
request.on('row', function(row) {
results.push(row);
});
console.log(results) // I can see results array perfectly here
connection.execSql(request);
//return callback(null, results); // Tried setting callback as parameter too in this function but got error "callback is not a function"
}
When I call the statement function outside like this:
var sqlquery = new checkId(passid);
console.log(sqlquery);
I get:
"sqlquery {}"
I other words, an [object Object] but empty (obviously, JSON.strinfigy in empty it's useless). I already tried to use callback as a workaround as commented in the code above but got error, how can I see results array when I call the function ?
Knowing that Tedious it's async and results won´t process on time to get them outside (reason why it´s empty object) and since there´s no specific answer to this anywhere (a lot of theory yes, but not a clear explanation due that some code it´s outdated like curiosly where you use callback as a set function, there´s no guidance of how to mix promises with Tedious properly, answers only show results in console.log or some people may be beginners with the sync/async concept), I post here a commented way that worked for me in case anyone may need it:
///Connection
var Connection = require('tedious').Connection;
var config = {
server: 'myserver.database.windows.net',
authentication: {
type: 'default',
options: {
userName: 'myusername',
password: 'mypassword',
rowCollectionOnDone: true,
rowCollectionOnRequestCompletion: true
}
},
options: {
encrypt: true,
database: 'mydatabase'
}
};
const connection = new Connection(config);
connection.on('connect', function(err) {
if (err) {
console.log(err);
}else{
console.log("Connected");
}
});
var Request = require('tedious').Request
var TYPES = require('tedious').TYPES;
Now , inside an async function you can call this example query with params (must be inside async function in order to use 'return await' and that everything syncs to avoid empty data :
async your_function(){
var id = 'id you want or user inputs';
const allData = [];
// We now set the promise awaiting it gets results
await new Promise((resolve,reject) => {
const request = new Request("SELECT * FROM table WHERE field = #id", function(err, rowCount) {
if (err) {
return reject(err);
} else {
console.log(rowCount + ' rows');
}
});
request.addParameter('id', TYPES.NVarChar, id); //Param id declaration
request.on('row', function(columns) {
columns.forEach(function(column) {
allData.push(column.value); //Push the result to array
});
});
request.on('doneProc', function (rowCount, more, returnStatus, rows) {
console.log('onDoneProc');
return resolve(allData); //Here we resolve allData using promise in order to get it´s content later
});
connection.execSql(request);
});
var mydata = allData; // Now You can assign it or use the same object as well
}
Hope it helps someone as it did to me.
I have the following AWS lambda handler:
exports.handler = async (event, data) => {
var AWS = require('aws-sdk/global');
const awsParamStore = require('aws-param-store');
const {
Pool
} = require('pg');
var host;
await awsParamStore.getParameter('testing-main-rds-url', { //get database host from AWS
region: 'us-east-1'
})
.then((parameter) => {
host = parameter.Value
});
var signer = await new AWS.RDS.Signer({
region: 'us-east-1',
username: 'developer',
hostname: host,
port: 5432
});
var token = await signer.getAuthToken({}); //get token from AWS
const db = await new Pool({
user: "developer",
host: host,
database: "main",
password: token,
port: 5432,
ssl: true,
});
const query = `INSERT INTO crm.user_crm
(u_id,username)
VALUES ($1,$2)`;
const values = [event.u_id, event.username];
db.connect((err, client, release) => {
if (err) {
throw("Error acquiring client.", err.stack);
} else {
client.query(query, values, (err, result) => {
release();
if (err) {
throw("Error executing query.", err.stack);
return ;
} else {
console.log("INSERT DONE");
db.end()
return {
statusCode: 200
};
}
})
}
})
};
This code will take in data and add it to a database.
When I run it on my computer with console.log(require('./index').handler(data)); it works perfectly and inserts the record. When I run it from lambda it returns nothing and doesn’t insert a record. Any help would be appreciated.
You mixing async/await with callback style. Your lambda function will finish before the query finish.
As example in pg document it supports async/await:
Instead of db.connect((err, client, release) => {...
const res = await pool.query(query, values);
console.log("INSERT DONE");
await pool.end()
return {
statusCode: 200
};
I'm trying to make REST apis with the serverless framework.
Some of the functions are asynchronous.
So I'm using Promise.
But the promise is not working (no response)
So, I'm using the await keyword. It works fine.
I think this is bad way. How to use promise in serverless framework?
Any advice or suggestion would be appreciated. Thank you in advance.
You can use the promise of many ways. Personally, separate the promise in another function.
I made a example with request module:
const request = require("request");
// The promise
const requestPromise = (url, options) =>
new Promise((resolve, reject) => {
options = options || {};
const processRequest = (err, response) => (err ? reject(err) : resolve(response));
request(url, options, processRequest);
});
// You can use like this
module.exports = (event,context) => {
let url = event.url;
requestPromise(url)
.then(response => {
// Do something
context.succeed({succeed: true /* put return data here */})
})
.catch(details => context.fail({error: true, details: details}));
}
// Or this
module.exports = async (event,context) => {
try {
let url = event.url;
let response = await requestPromise(url);
// Do something
context.succeed({succeed: true /* put return data here */});
} catch (details) {
context.fail({error: true, details: details});
}
}
If you use async/wait, you need add try/catch to handler errors.
I am coding a serverless-kubeless api now for the mysql world database. I had to solve this problem yesterday. I arrived at the following solution. It's not feature complete. But you didn't ask for that. So here is a working GET endpoint which accepts various query parameters to customise the query.
'use strict';
const pool = require('./database');
module.exports.handler = async (event, context) => new Promise((resolve, reject) => {
let request = event.extensions.request;
let response = event.extensions.response;
try{
let handleResults = (err, results, fields) => {
if(err){
response.status(500).send({
success: false,
message: err.message,
});
}else{
response.status(200).send({
success: true,
count: results.length,
data: results,
});
}
}
if(typeof(request.query.id) !== "undefined"){
// search for a specific region by id
if (Number.isNaN(Number(request.query.id))) {
response.status(500).send({
success: false,
message: "id query param was not a number",
});
}
pool.query("select id,name,code,country_id from regions where id = ?", [request.query.id], handleResults);
}else if(typeof(request.query.country) !== "undefined"){
// search for a region list from a specific country
if (Number.isNaN(Number(request.query.country))) {
response.status(500).send({
success: false,
message: "country query param was not a number",
});
}
pool.query("select id,name,code,country_id from regions where country_id = ?", [request.query.country], handleResults);
}else{
response.status(400).send({
success: false,
message: "Could not find country, or region query parameter. Require a search term"
});
}
}catch(exception){
response.status(500).send({
success: false,
message: exception.message
});
}
});
and database.js:
const mysql = require("mysql");
const util = require('util');
const pool = mysql.createPool({
connectionLimit: 10,
host: process.env.DATABASE_HOSTNAME,
user: process.env.DATABASE_USERNAME,
port: process.env.DATABASE_PORT,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE_NAME,
});
pool.getConnection((err, connection) => {
if (err) {
if (err.code === 'PROTOCOL_CONNECTION_LOST') {
console.error('Database connection was closed.');
}
if (err.code === 'ER_CON_COUNT_ERROR') {
console.error('Database has too many connections.');
}
if (err.code === 'ECONNREFUSED') {
console.error('Database connection was refused.');
}
}
if (connection) connection.release();
return;
});
// Magic happens here.
pool.query = util.promisify(pool.query);
module.exports = pool;
I commonly do stuff with Promises in my serverless projects:
//this would me in a module like: services/myhttpservice.js (for example)
//wrap the GET HTTP request in a Promise
module.exports.GetUrlPromise = function(url, cookie_session_value) {
console.log(new Date().getTime() + " GetUrlPromise() CALLED: " + url);
var j = request.jar();
if(cookie_session_value){
var cookie1 = request.cookie(cookie_name + '=' + cookie_session_value);
j.setCookie(cookie1, cookie_domain);// domain used by the cookie, maybe make more generic?
}
// create the "Basic" auth header
var auth = "Basic " + Buffer.from(basic_username + ":" + basic_password).toString("base64");
//create request options
var options = {
'method': 'GET',
'url': url,
'jar': j,
'headers': {
'Authorization': auth,// set Basic auth header that is the base64 of the un:pw combo
'Content-Type': 'application/json'
}
};
return new Promise((resolve, reject) => {
request(options, function (error, response, body) {
if(error){
console.log('error:', error);
reject(error);
}else{
console.log('statusCode:', response && response.statusCode);
// object for returning response results
var http_resp = {};
http_resp._session = GetCookieValue(response);
http_resp.body = body;
http_resp.statusCode = response.statusCode;
//http_resp.response = response;
http_resp.requestType = 'GET';
console.log(JSON.stringify(http_resp));
resolve(http_resp);
}
});
});
}
It gives me the ability to make promised calls to my services easily:
//in my controller code:
myhttpservice.GetUrlPromise(page_url, user_session)
.then((http_resp)=>{ etc...
Await and async are not bad practices if used correctly.
If you don't have promises depending on each other you can call them in 'parallel' by adding all promises (without await) in an array and use const responses = await Promise.all(promisesArray) to wait for all responses to be successful.
For more information refer to this answer which explains very well Call async/await functions in parallel
I'm getting undefined when I trying to print a value to console which is returned by an asynchronous function.
This is happening in my controller function (dumyController.js) which calls a function written in helper (DBHelper.js), for DRY approach, which
asynchronously fetches data from a model function in DBHelperModel.js
dumyController.js
var dbHelpers = require('../helpers/helpers');
exports.dumyControllerFunc = function (req, res) {
var result= dbHelpers.dumyHelperFunc(165);
console.log(result);
};
DBHelper.js
var dbHelp = require('../models/DBHelperModel');
module.exports = {
dumyHelperFunc: function (userId) {
dbHelp.fetchDataFromDB(userId, function (err, rows) {
var res;
if (err) {
return null;
}
else {
res.send(rows.member_code);
}
});
}
};
DBHelperModel.js
var db = require('../db');
var DBHelpers = {
fetchDataFromDB: function (userId, callback) {
var query = `SELECT member_code FROM members where id=?`;
db.query(query, userId, callback);
},
};
module.exports = DBHelpers;
db.js
var mysql = require('mysql');
var connection = mysql.createPool({
host: '127.0.01',
user: 'root',
password: '',
database: 'dumyDB'
});
module.exports = connection;
I know I'm not getting value because of the asynchronous nature of the function but can anyone tell me how to fetch the value with an architecture like given above. I'm new to nodeJS. Thanks!
I think you want a solution about the asynchronous in nodejs.
The promise,that is a universal and popular solution
Use a callback,That is a approach in nodejs's way,anyway,that is native nodejs's asynchronous solution .
Other asysn: Generate and async, that's es6 feature,and the latter is support by nodejs7+
The promise is most recommend,it has a good looks structure if has a asycn chain, The callback looks bad on that.
This is probably what you trying to achieve:
https://repl.it/MA0Z/0
var DBHelpers = {
fetchDataFromDB: function (userId, callback) {
callback(null, 'hello fetchDataFromDB');
},
};
var dbhelp = {
dumyHelperFunc: function (userId, callback) {
DBHelpers.fetchDataFromDB(userId, function (err, rows) {
if (err) {
callback('error bro');
} else {
callback(null, rows);
}
});
}
}
dbhelp.dumyHelperFunc(165, function (error, result) {
console.log(result);
});
I got a problem with Multer, undefined req.files.path field
First, my Express.js route is:
routes.js
router.post('/', function(req, res, next){
// id, name, usersArray[], info, iconImg, headerImg
var dataObject = new MyMongooseDataObject();
// Receive data
dataObject.id = uuid.v4();
dataObject.name = req.body.name;
dataObject.usersArray = req.body.usersArray;
dataObject.info = req.body.info;
return someBindingWrapperToStoreTheFile.postFile(uuid.v4(), [req.files.iconImg.path.toString(), req.files.headerImg.path.toString()])
.then(function (postedFiles) {
dataObject.iconImg = postedFiles.body.payload.files[0].id;
dataObject.headerImg = postedFiles.body.payload.files[1].id;
//save dataObject after storing images and processing data
dataObject.save(function(savedDataObject){
next(success(req, 200, 'dataObject Saved ' + savedDataObject.id));
});
})
.catch(function(err){
console.log('FAILED: ', err.stack);
return next(failure(req, 500, err));
});
});
When I test my route with a separate small requestJS script, it works just fine:
HTTP rest api request test with requestJS
postDataObject.js
var request = require('request');
var fs = require('fs');
var uuid = require('uuid');
var formData = {
name: 'someName',
info: 'Some INFO and text description. ',
'usersArray[0][uuid]': uuid.v4().toString(),
'usersArray[1][uuid]': uuid.v4().toString(),
'usersArray[2][uuid]': uuid.v4().toString(),
// handle files
iconImg: fs.createReadStream('/var/tmp/img/iconImg.png'),
headerImg: fs.createReadStream('/var/tmp/img/headerImg.png')
};
request.post({url:'http://127.0.0.1:2233/api/postDataObject', formData: formData}, function (err, httpResponse, body) {
if (err) {
return console.error('failed:', err);
}
console.log('DataObject creation is successful! Server responded with:', body);
});
Now I'm writing the wrapper library for the fronted usage, when I use the same code in another context, it seems, that Multer handling req.files.headerImg.path is not working, it's undefined.
The code I use for wrapper library:
wrapper-lib.js
var request = require('request'),
URI = require('URIjs'),
fs = require('fs'),
uuid = require('uuid'),
path = require('path'),
Promise = require('bluebird'),
_ = require('lodash'),
DataObjectBindings.prototype.createDataObject = function (jsonRequestJSFormData) {
var self = this;
// this give the URL of the API to make requests to
return self.getAPIurlHelper().then(function (apiUrl) {
return new Promise(function (resolve, reject) {
request.post({url: apiUrl, form: jsonRequestJSFormData}, function (err, res, body) {
if (err) {
reject(err);
} else {
resolve({res: res, body: JSON.parse(body)});
};
}); //end of .post
}); // end of Promise
}); // end of getAPIurlHelper() function
}; // end of createDataObject function definition
And Finally I test the warpper with:
wrapper-test.js
// Instantiate Broker Client
var Wrapper = require('./wrapper-lib');
var wi; //wrapper instalnce
var ConnectApiRequestTracer = require('./connectApiRequestTracer');
var fs = require('fs');
ConnectApiRequestTracer().connect()
.then(function () {
wi = new Wrapper();
return wi.createDataObject(
uuid.v4(),
{
name: 'Some Cool Name',
info: 'Some nice description and info. ',
'usersArray[0][uuid]': uuid.v4().toString(),
'usersArray[1][uuid]': uuid.v4().toString(),
'usersArray[2][uuid]': uuid.v4().toString(),
iconImg: fs.createReadStream('/var/tmp/img/iconImg.png'),
headerImg: fs.createReadStream('/var/tmp/img/headerImg.png'),
);
})
.then(function (data) {
console.log('SUCCESS: ', data);
})
.catch(function (err) {
console.log('FAILED', err.stack);
});
When I run the test case wrapper-test.js, it throws me an error, that says the req.files.iconImg.path is undefined.
Any ideas what can be wrong?
try using :
req.file.iconImg.path
req.file.headerImg.path
instead of req.files.iconImg.path and req.files.headerImg.path