Azure functions integration with Postgres in Node.js - node.js

I want to access to Azure Postgres DB from an Azure function.
Below is the node.js source code of Azure function.
module.exports = async function (context, req) {
try {
context.log('Start function!');
var pg = require('pg');
const config = {
host: 'taxiexample.postgres.database.azure.com',
user: 'postgres#taxiexample',
password: 'QscBjk10;',
database: 'taxi',
port: 5432,
ssl: false
};
var client = new pg.Client(config);
const query = 'insert into taxi values (\'2\');';
context.log(query);
client.connect();
var res = client.query(query);
await client.end();
context.log(res);
} catch (e) {
context.log(e);
} finally {
context.res = {
status: 200,
body: "ok"
};
}
};
The record doesn't insert, the res object returns the following error:
2020-03-04T23:03:59.804 [Information] Promise {
<rejected> Error: Connection terminated
at Connection.<anonymous> (D:\home\site\wwwroot\HttpTrigger1\node_modules\pg\lib\client.js:254:9)
at Object.onceWrapper (events.js:312:28)
at Connection.emit (events.js:228:7)
at Socket.<anonymous> (D:\home\site\wwwroot\HttpTrigger1\node_modules\pg\lib\connection.js:78:10)
at Socket.emit (events.js:223:5)
at TCP.<anonymous> (net.js:664:12)
}
2020-03-04T23:03:59.811 [Information] Executed 'Functions.HttpTrigger1' (Succeeded, Id=944dfb12-095d-4a28-a41d-555474b2b0ee)
Can you help me? Thanks

I've resolve it, it was a trivial programming error.
Below is the correct source code
module.exports = async function (context, req) {
try {
context.log('Start function!');
var pg = require('pg');
const config = {
host: 'example.postgres.database.azure.com',
user: 'postgres#example',
password: 'passwd;',
database: 'test',
port: 5432,
ssl: true
};
var client = new pg.Client(config);
const query = 'insert into test values (\'2\');';
context.log(query);
client.connect(err => {
if (err) {
console.error('connection error', err.stack);
} else {
console.log('connected');
client.query(query, (err, res) => {
if (err) throw err;
console.log(res);
client.end();
})
}
});
} catch (e) {
context.log(e);
} finally {
context.res = {
status: 200,
body: "ok"
};
}
};

Related

AWS lambda api Postgres not won’t insert

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
};

tunnel-ssh throws an error after getting connected

I'm trying to connect to mongodb(mongodb package) using the tunnel-ssh package. It gets connected and I can log the db but it immediately throws an error and disconnects.
buffer.js:705
throw new ERR_INVALID_ARG_TYPE(
^
TypeError [ERR_INVALID_ARG_TYPE]: The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type undefined
at Function.byteLength (buffer.js:705:11)
at SSH2Stream.directTcpip (D:\WORK\node_modules\ssh2-streams\lib\ssh.js:1128:23)
at openChannel (D:\WORK\node_modules\ssh2\lib\client.js:1142:21)
at Client.forwardOut (D:\WORK\node_modules\ssh2\lib\client.js:994:10)
at Client.<anonymous> (D:\WORK\node_modules\tunnel-ssh\index.js:16:23)
at Client.emit (events.js:223:5)
at SSH2Stream.<anonymous> (D:\WORK\node_modules\ssh2\lib\client.js:601:10)
at Object.onceWrapper (events.js:312:28)
at SSH2Stream.emit (events.js:223:5)
at parsePacket (D:\WORK\node_modules\ssh2-streams\lib\ssh.js:3911:10) {
code: 'ERR_INVALID_ARG_TYPE'
}
This is my code.
const tunnel = require("tunnel-ssh");
const config = require("config");
const MongoClient = require("mongodb").MongoClient;
const connection = new Promise((resolve, _) => {
// eslint-disable-next-line
tunnel(config.get("server"), async (err, server) => {
server.on("connection", console.log.bind(console, "server error"));
const client = await MongoClient.connect(config.get("mongodb").url, {
useUnifiedTopology: true,
useNewUrlParser: true
});
client.on("error", console.error.bind(console, "mongodb error"));
resolve({ client });
});
});
async function runQuery() {
const { client} = await connection;
console.log(client);
}
runQuery();
There is no problem with config. In fact, the logging in runQuery function works but throws that error immediately.
I have not used the tunnel-ssh package you have mentioned, but I went through the docs and I see that you are using it wrong. I simply copied the configuration given in the docs of tunnel-ssh and it started working for me. pasting the entire code below
const tunnel = require("tunnel-ssh");
const MongoClient = require("mongodb").MongoClient;
const connection = new Promise((resolve, _) => {
// eslint-disable-next-line
tunnel(
{
username: "root",
Password: "secret",
host: "127.0.0.1",
port: 22,
dstHost: "127.0.0.1",
dstPort: 27017,
localHost: "127.0.0.1",
localPort: 27000
},
async (err, server) => {
server.on("connection", console.log.bind(console, "server error"));
const client = await MongoClient.connect(
"mongodb://localhost:27017/user",
{
useUnifiedTopology: true,
useNewUrlParser: true
}
);
client.on("error", console.error.bind(console, "mongodb error"));
resolve({ client });
server.close();
}
);
});
async function runQuery() {
const { client } = await connection;
console.log("Connection Successful");
}
runQuery();
The part where you went wrong is passing string to tunnel package. it expects configuration object not string.

How can I make my Hapi route wait for data before returning a value?

I am using Hapi.js and have a route that I want to use to fetch data and then return a result.
I have tried to use async/await, but I must be doing something wrong because while the function I am calling eventually prints a result to the console, the route is returning without waiting for that function to return a value.
'use strict';
const Hapi = require('#hapi/hapi');
const HandyStorage = require('handy-storage');
var ethBalance ='';
// Connection to public blockchain via Infura.io
const Web3 = require("web3");
const web3 = new Web3(new Web3.providers.HttpProvider("https://mainnet.infura.io/v3/cf44bc52af3743bcad5f0b66813f8740"));
// Initialize Handy Storage
const storage = new HandyStorage({
beautify: true
});
//Get ETH address from Handy Storage
storage.connect('./preferences.json');
var walletAddress = storage.state.wallet;
// Get wallet balance
const getWalletBalance = async () => {
web3.eth.getBalance(`${walletAddress}`, async function(err, result) {
if (err) {
console.log('There was an error: ' + err);
return ({ error: 'The wallet balance call failed.' });
} else {
ethBalance = await web3.utils.fromWei(result, "ether");
console.log("This should be first: The wallet balance via API call is " + ethBalance + " ETH.");
return ethBalance; // I expect the walletbalance route to wait for this to be returned
}
});
};
// API Server
const init = async () => {
// Connection settings
const server = Hapi.server({
port: 3000,
host: 'localhost'
});
// Get wallet balance
server.route({
method: 'GET',
path: '/walletbalance/',
handler: async (request, h) => {
let result = null;
try {
result = await getWalletBalance();
console.log('This should be second, after the getWalletBalance function has printed to the console.'); // this prints first, so await isn't working as expected
return ({ ethBalance: result });
} catch (err) {
console.log('Error in walletbalance route');
}
}
});
// 404 error handling
server.route({
method: '*',
path: '/{any*}',
handler: function (request, h) {
return ({
message: 'Error!'
});
}
});
await server.start();
console.log('Server running on %s', server.info.uri);
};
process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});
init();
Any idea where I have gone wrong here? This is the first time I have used async/await.
ETA: My console looks like this:
[nodemon] starting `node index.js`
Server running on http://localhost:3000
This should be second, after the getWalletBalance function has printed to the console.
This should be first: The wallet balance via API call is 4061.894069996147660079 ETH.
And this is the JSON I get back when I use the wallet balance route:
{}
Based on the answer I was given, I was able to get the results I wanted with this:
'use strict';
const Hapi = require('#hapi/hapi');
const HandyStorage = require('handy-storage');
var ethBalance ='';
// Connection to public blockchain via Infura.io
const Web3 = require("web3");
const web3 = new Web3(new Web3.providers.HttpProvider("https://mainnet.infura.io/v3/cf44bc52af3743bcad5f0b66813f8740"));
// Initialize Handy Storage
const storage = new HandyStorage({
beautify: true
});
//Get ETH address from Handy Storage
storage.connect('./preferences.json');
var walletAddress = storage.state.wallet;
// Get wallet balance
async function getWalletBalance(){
let ethBalance = await web3.eth.getBalance(`${walletAddress}`);
if (ethBalance.err) {
console.log('error in the called function');
} else {
return ethBalance;
}
}
// API Server
const init = async () => {
// Connection settings
const server = Hapi.server({
port: 3000,
host: 'localhost'
});
// Get wallet balance
server.route({
method: 'GET',
path: '/walletbalance/',
handler: async (request, h) => {
try {
const result = await getWalletBalance();
const ethBalanceInWei = web3.utils.fromWei(result, "ether");
return ({ balance: ethBalanceInWei });
} catch (err) {
console.log('Error in walletbalance route');
}
}
});
// 404 error handling
server.route({
method: '*',
path: '/{any*}',
handler: function (request, h) {
return ({
message: 'Error!'
});
}
});
await server.start();
console.log('Server running on %s', server.info.uri);
};
process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});
init();
Thank you for the help! That got me going in the right direction.
Basically your getWalletBalance function is using multiple concepts. callback style functions and inside that you are using await. I have restructured your code a little bit. Hopefully that should fix the issue which you are facing.
'use strict';
const Hapi = require('#hapi/hapi');
const HandyStorage = require('handy-storage');
var ethBalance ='';
// Connection to public blockchain via Infura.io
const Web3 = require("web3");
const web3 = new Web3(new Web3.providers.HttpProvider("https://mainnet.infura.io/v3/cf44bc52af3743bcad5f0b66813f8740"));
// Initialize Handy Storage
const storage = new HandyStorage({
beautify: true
});
//Get ETH address from Handy Storage
storage.connect('./preferences.json');
var walletAddress = storage.state.wallet;
function getWalletBalance() {
return Promise((resolve, reject) => {
web3.eth.getBalance(`${walletAddress}`, (err, result) => {
if (err) {
console.log('There was an error: ' + err);
reject({ error: 'The wallet balance call failed.' });
} else {
resolve(result);
}
});
});
}
// API Server
const init = async () => {
// Connection settings
const server = Hapi.server({
port: 3000,
host: 'localhost'
});
// Get wallet balance
server.route({
method: 'GET',
path: '/walletbalance/',
handler: async (request, h) => {
try {
const result = await getWalletBalance();
ethBalance = await web3.utils.fromWei(result, "ether");
return ethBalance;
} catch (err) {
console.log('Error in walletbalance route');
}
}
});
// 404 error handling
server.route({
method: '*',
path: '/{any*}',
handler: function (request, h) {
return ({
message: 'Error!'
});
}
});
await server.start();
console.log('Server running on %s', server.info.uri);
};
process.on('unhandledRejection', (err) => {
console.log(err);
process.exit(1);
});
init();

How to get the mssql output in protractor + VSCode

I'm running the below code seems like the connection is made successfully but i do not see any output or is there any way to see the output of the query result, I'm new to this protractor nodeJS MSSQL connection.
const assert = require("../configuration.js");
const { config } = require("dotenv");
const { ConnectionPool } = require("mssql");
var sql = require('mssql');
config();
const c = {
driver: 'msnodesqlv8',
server: "server/nameORIP",
user: "UserName",
password: "Password",
database: 'DBname',
};
describe("mssql connection", () => {
it('test query', () => {
sql.connect(config, (err) => {
if (err) console.log(err);
// create Request object
var request = new sql.Request();
// query to the database and get the records
request.query('select * from NetUsers', (err, recordset) => {
if (err) console.log(err)
// send records as a response
request.send(recordset);
});
}); // end of sql.connect()
}) // end of it
})
Output
Request {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
canceled: false,
_paused: false,
parent: [Function: ConnectionPool],
parameters: {},
rowsAffected: 0 }
I didn't find any information for the method request.send(recordset); from their official documentation.
Supported methods in Request Object are:
execute - https://www.npmjs.com/package/mssql#execute
input - https://www.npmjs.com/package/mssql#input
output - https://www.npmjs.com/package/mssql#output
pipe - https://www.npmjs.com/package/mssql#pipe
query - https://www.npmjs.com/package/mssql#query
batch - https://www.npmjs.com/package/mssql#batch
bulk - https://www.npmjs.com/package/mssql#bulk
cancel - https://www.npmjs.com/package/mssql#cancel
request.query function will give you the list of records from the DB and pass it to the callback function and the values can be accessed directly using
request.query('select * from NetUsers', (err, resultArray) => {
if (err) console.log(err)
// if no error
console.log(resultArray.recordset[0]); //will print the first row from response.
});
Refer : https://www.npmjs.com/package/mssql#query-command-callback
I finally made it to work with few changes not only it connects but also runs the query and shows me the output in console, once again thank you for all the help.
import { async } from "q";
const sql = require('mssql/msnodesqlv8');
const assert = require("../configuration.js");
const poolPromise = new sql.ConnectionPool({
driver: 'msnodesqlv8',
server: "server/nameORIP",
user: "UserName",
password: "Password",
database: 'DBname',
})
.connect()
.then(pool => {
console.log('Connected to MSSQL')
return pool
})
.catch(err => console.log('Database Connection Failed! Bad Config: ', err))
;
describe('any test', () => {
it('verification', async () => {
try
{
const pool = await poolPromise;
const result = await pool.request()
.query('SELECT TOP (10) * FROM dbo.NetUsers')
console.log(result);
}
catch(err)
{
console.log(err);
}
});
});

node-mysql unable to handle multiple queries?

I am using: node-mysql
arrtickers got around 200 values.
arrtickers closure pass in values into sym.
sym will pass in value to each function (running in async mode, each fn will start running on its own without waiting for the previous fn to complete)
problem here is mysql seems unable to handle multiple calls?
events.js:48
throw arguments[1]; // Unhandled 'error' event
^
Error: reconnection attempt failed before connection was fully set up
at Socket.<anonymous> (/home/ubuntu/node/node_modules/mysql/lib/client.js:67:28)
at Socket.emit (events.js:64:17)
at TCP.onread (net.js:398:51)
arrtickers.forEach(function(value) {
var sym= value;
(function(sym) {
url2= "http://test2.com/quote.ashx?t="+sym+"&ty=c&ta=1&p=d&b=1";
request({ uri:url2 }, function (error, response, body) {
jsdom.env({
html: body,
scripts: [
jqlib
]
}, function (err, window) {
var $ = window.jQuery;
var data= $('body').html();
//some scrapping
var client2 = mysql.createClient({
user: 'root',
password: '123',
host: '127.0.0.1',
port: '3306'
});
client2.query('USE testtable');
sql= "update tbla SET a='"+a+"', b='"+b+"', c='"+c+"', d='"+d+"' where ticker='"+sym+"'";
client2.query(
sql, function(err, info){
if (err) {
throw err;
}
}
);
client2.end();
});
});
})(sym);
(function(sym) {
url= "http://test3.com/quote.ashx?t="+sym+"&ty=c&ta=1&p=d&b=1";
request({ uri:url3 }, function (error, response, body) {
jsdom.env({
html: body,
scripts: [
jqlib
]
}, function (err, window) {
var $ = window.jQuery;
var data= $('body').html();
//some scrapping
var client3 = mysql.createClient({
user: 'root',
password: '123',
host: '127.0.0.1',
port: '3306'
});
client3.query('USE testtable');
sql= "update tbla SET a='"+a+"', b='"+b+"', c='"+c+"', d='"+d+"' where ticker='"+sym+"'";
client3.query(
sql, function(err, info){
if (err) {
throw err;
}
}
);
client3.end();
});
});
})(sym);
(function(sym) {
url= "http://test4.com/quote.ashx?t="+sym+"&ty=c&ta=1&p=d&b=1";
request({ uri:url4 }, function (error, response, body) {
jsdom.env({
html: body,
scripts: [
jqlib
]
}, function (err, window) {
var $ = window.jQuery;
var data= $('body').html();
//some scrapping
var client4 = mysql.createClient({
user: 'root',
password: '123',
host: '127.0.0.1',
port: '3306'
});
client4.query('USE testtable');
sql= "update tbla SET a='"+a+"', b='"+b+"', c='"+c+"', d='"+d+"' where ticker='"+sym+"'";
client4.query(
sql, function(err, info){
if (err) {
throw err;
}
}
);
client4.end();
});
});
})(sym);
//same function repeat for test5.com, test6.com, test7.com, test8.com, test9.com
});
Below is portion of the code from client.js (part of node-mysql)
I don't really understand how the whole process get linked together, any idea guys?
Client.prototype._connect = function() {
this.destroy();
var socket = this._socket = new Socket();
var parser = this._parser = new Parser();
var self = this;
socket
.on('error', this._connectionErrorHandler())
.on('data', parser.write.bind(parser))
.on('end', function() {
if (self.ending) {
// #todo destroy()?
self.connected = false;
self.ending = false;
if (self._queue.length) {
self._connect();
}
return;
}
if (!self.connected) {
this.emit('error', new Error('reconnection attempt failed before connection was fully set up'));
return;
}
self._connect();
})
.connect(this.port, this.host);
parser.on('packet', this._handlePacket.bind(this));
};
You can use node-mysql-queues module, which is a wrapper for the current module you are using. Here is the information: https://github.com/bminer/node-mysql-queues
Sample Multi-Query from their page:
var q = client.createQueue();
q.query(...);
q.query(...);
q.execute();
client.query(...); //Will not execute until all queued queries (and their callbacks) completed.

Resources