NODE JS | MS API facing issues while multiple connection connected to API - javascript

I just wanted to be so clear as I can, So I have an MS SQL nodejs API, through which I interact with my android and Desktop Application. Currently its working fine, but it is not on pool connection. I think that is why when more people use my app it just doesn't give the response and gives an error more LIKE
Connection already exists close SQL.close() first
So I was planning on upgrading my API to pool connection, by which means more people can connect to my API simultaneously. Right?
So I have this connection to the DB code that has the connection and query look like this :
Connection var dbConfig = {
user: 'sa',
password: "pmis13",
server: '19',
database: 'CUBES_HO',
};
Query handler :
function executeQuery(query) {
return new Promise((resolve, reject) => {
sql.connect(dbConfig, function (err) {
if (err) {
reject(err);
sql.close();
} else {
// create Request object
var request = new sql.Request();
// query to the database and get the records
request.query(query, function (err, data) {
if (err) {
reject(err);
sql.close();
} else {
resolve(data);
sql.close();
}
});
}
});
});}
And the query look like this :
app.get("/dailysale/:date", function (req, res) {
var query = "SELECT SUM(bill_amt) AS totalSale FROM [CUBES_HO].[dbo].[vw_bill_summary] where inv_loc_key = 2 and bill_sale_date = '"+req.params.date+"'";
executeQuery(query)
.then((data) => {
res.status(200).send({ "msg": "Records fetched", "data": data.recordsets });
}).catch((err) => {
res.status(500).json({ "msg": err.message });
});});
I want to convert this or we can say upgrade this api to pool connection, which sounds more reliable for multiple connection. Correct me I am wrong.

I couldn't put this link in the comments section so posting it here. This answer on SO explains difference between mysql.createConnection and mysql.createPool.
An example to help you create pool connection
const pool = new sql.ConnectionPool({
user: '...',
password: '...',
server: 'localhost',
database: '...'
})
Found it here.

I found a work arround by doing this
var config ={
user: 'sa',
password: "pdt09",
server: '3',
database: 'CUBES',
options: {encrypt: true}
};
async function executeQuery(sqlquery) {
return new Promise(function(resolve, reject) {
(async() => {
const pool = new sql.ConnectionPool(config);
pool.on('error', err => {
// ... error handler
console.log('sql errors', err);
});
try {
await pool.connect();
let data = await pool.request().query(sqlquery);
resolve(data);
} catch (err) {
reject(err)
} finally {
pool.close(); //closing connection after request is finished.
}
})();
}).catch(function(err) {
});
}
and the worker will remain the same

Related

Close MSSQL connection in Node

I'm connecting with SQL Server using Node mssql package in my Electron app.
I can't create REST API.
It works fine although I have concerns:
it doesn't close SQL connection after query
it makes a new DB connection for each query
Is that ok?
How it works:
app.js makes 2 queries and logs results
sql.js connects with DB
// app.js
const { getUser, getUsers } = require('./sql');
getUser(10).then((result) => {
console.dir(result);
});
getUsers.then((result) => {
console.dir(result);
})
// sql.js
const sql = require("mssql");
// DB credentials
const config = {
user: 'myuser',
password: '123',
server: 'myserver',
database: 'mydb',
options: {
encrypt: true
}
}
// Creates new connection pool for each query
function connectDB() {
const pool = new sql.ConnectionPool(config);
return pool.connect()
.then(pool => {
console.log('Connected to database');
// returns Promise
return pool;
})
.catch(err => console.log('Database connection failed!', err));
}
// 1st query
function getUser(id) {
const connection = connectDB();
return connection
.then(pool => {
return pool.request()
.input('PK_ID', sql.Int, parseInt(id))
.execute('[uspGetUser]');
})
.then(result => {
return result.recordset[0];
})
.catch(err => {
console.log('Query failed!', err);
});
}
// 2nd query
function getUsers() {
const DB = connectDB();
return DB
.then(pool => {
return pool.request()
.execute('[uspGetUsers]');
})
.then(result => {
return result.recordset[0];
})
.catch(err => {
console.log('Query failed!', err);
});
}
module.exports = {
getUser,
getUsers
}
No, you don't need to close a.k.a. release a connection back to the connection pool after every query. The library already does that for you.
The pool.close() method will close all the connection in the pool. Technically, you should only do that when you're terminating your application, not after every query, since creating a new pool every time create quite an overhead on your application.
I had the same question myself, so I looked up the project's source code.
Solved!
To close DB connection and return results, we can use finally statement and asnyc/await functions.
The finally statement lets you execute code, after try and catch, regardless of the result.
// sql.js
const sql = require("mssql");
// DB credentials
const config = {
user: 'myuser',
password: '123',
server: 'myserver',
database: 'mydb',
options: {
encrypt: true
}
}
async function connectDB() {
const pool = new sql.ConnectionPool(config);
try {
await pool.connect();
console.log('Connected to database');
return pool;
}
catch(err) {
console.log('Database connection failed!', err);
return err;
}
}
async function getAll() {
const DB = await connectDB();
try {
const result = await DB.request()
.query('select * from [your_table]');
return result.recordset;
}
catch (err) {
console.log('Error querying database', err);
return err;
}
finally {
DB.close();
}
}
async function execute() {
let result = await getAll();
console.dir(JSON.stringify(result));
return result;
}
execute();

how to wait till DB connection is made and queries are executed for each database in an array

A file contains json data with details of database.
For each database connection, a series of queries need to be executed.
Currently, the map function is waiting for the database connection.
Below is the start function
function start() {
console.log('function initiated');
try {
let jsonData = fs.readFileSync('../request.json');
let jsonString = JSON.parse(jsonData);
//jsonString['request'].forEach(async function(json) {
jsonString['request'].map(async json => {
dbdetails = json.dbdetails;
//dbdetails.forEach(async function(db){
await dbbdetails.map(async db => {
console.log('pdbdetails: ' + db);
connString = json.connString;
//makes the DB connection
await connectDB(db.userId, db.Password, connString)
.then(async conn => {
await execution(conn, pdbDetails, vmUser, vmPassword, ip);
})
.catch(err => {
console.log(err);
});
console.log('after each execution');
//}
});
});
} catch (err) {
console.log(err.message);
return;
}
}
Below function is to make a database connection and return the connection
function connectDB(oUser, oPassword, connString) {
console.log('inside connectDB');
return new Promise((resolve, reject) => {
oracledb.getConnection(
{
user: oUser,
password: oPassword,
connectString: connString
},
function(err, connection) {
if (err) {
console.error(err.message);
reject(err);
//throw err;
}
console.log('returning connection');
//console.log(connection);
resolve(connection);
//return connection;
}
);
});
}
below is the function which executes servies of queries on database
function execution() {
/// series of sql query execution
}
Not sure what you’re trying to do exactly, but sounds like the problem is that .map doesn’t wait for your async functions. If you have to do them one at a time, use a for loop:
for ( var item of array ) {
await item.something();
}
To do them all at once:
var results = await Promise.all( array.map( item => item.something() )

Node js - How to use connection variable

I'm trying to create a database connection structure that allow multi database connections but I'm having problems about saving the connection so I can use in mssql.request().
I login form the user has to choose which database wants to use, so I'm thinking in trigger the select box database with this code that works fine.
LoginController.js
setDB: (req, res) =>
{
var connection = db.setDB(req.params.dbname);
connection.then(result => {
res.send(result);
});
},
db.setDB
const mssql = require('mssql');
module.exports =
{
setDB: (req, res) =>
{
console.log('Prepare to connect to ' + req);
return new Promise(function (resolve, reject){
var result = makeConnection(req);
result.then(value => {
console.log('result: ' + value);
if(value == 0)
{
console.log('Unknown database!');
resolve('Unknown database!');
}
else if(value == 1)
{
console.log('Error trying to connect! Maybe wrong connection data.');
resolve('Error trying to connect! Maybe wrong connection data.');
}
else if(value == 2)
{
console.log('Connection Done!');
resolve('Connection Done!');
}
}).catch(err => {
console.log(err);
console.log('Error handle setDB() results.');
reject('Error handle setDB() results! Call tech guy.');
});
})
//return connection;
}
}
function makeConnection(dbname)
{
return new Promise(function (resolve, reject){
console.log('Start connection....');
const configs = {
Emp1: {
user: "us",
password: "pass",
server: "ip",
database: "Emp1",
pool: {
max: 20,
min: 0,
idleTimeoutMillis: 900000
}
},
Emp2: {
user: "us",
password: "pass",
server: "ip",
database: "Emp2",
pool: {
max: 20,
min: 0,
idleTimeoutMillis: 900000
}
}
};
var config = configs[dbname];
if(config == undefined)
{
resolve(0);
}
global.conn = new mssql.Connection(config);
conn.connect(function(err)
{
if (err) {
console.log(err);
resolve(1);
} else {
console.log('Database Connected!');
resolve(2);
}
});
});
}
I do this global.conn = new mssql.Connection(config); to try to save the connection.
Now if I try to access a link(index) that do a query I have error because conn is not defined ...
var db = require('../config/db');
var mssql = require('mssql');
var squel = require("squel");
var request = new mssql.Request(conn);
module.exports =
{
index: (req, res) => {
console.log("User Index");
request.query("SELECT * from us",(err, records) => {
console.log(err);
//console.log(records);
res.send(records[0].username);
});
}
}
I appreciate a lot your opinion about the better way to do this, I don't see much information about multi database connection.
The user has to choose database in login form but after I have to save the database name but how? I already think in cache... I don't know, I need really some advices.
Any doubt about that ask me please.
Thank you

Nodejs rest service

I am trying to create REST service using Nodejs and Mysql.
his is my code:
var sqlDb = require("mysql");
var settings = require("../settings");
exports.executeSql = function (sql, callback) {
var conn = sqlDb.createConnection(settings.dbConfig);
conn.connect()
.then(function () {
var req = new sqlDb.Request(conn);
req.query(sql)
.then(function (recordset) {
callback(recordset);
})
.catch(function (err) {
console.log(err);
callback(null, err);
});
})
.catch(function (err) {
console.log(err);
callback(null, err);
});
};
But I have an error
.then(function(){
^
TypeError: cannot read property 'then' of undefined
Can anybody help me to solve this problem?
The correct function is createConnection. Read the docs please:
https://www.npmjs.com/package/mysql#introduction
In the documentation, the connect method is not returning a promise if you look at the documentation this can work as callback method:
var connection = mysql.createConnection({
host : 'example.org',
user : 'bob',
password : 'secret'
});
//** Look here...
connection.connect(function(err) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}
console.log('connected as id ' + connection.threadId);
});
As a good alternative, you can use the package promise-mysql that is using bluebird and you can locate here (which I strongly suggest to use) or you can wrap it up in a promise like using bluebird like:
async function connect(connection) {
return new Promise((resolve, reject) => {
connection.connect((err) => {
return err ? reject(err) : resolve(connection);
})
});
}

Using Node.js to connect to a REST API

Is it sensible to use Node.js to write a stand alone app that will connect two REST API's?
One end will be a POS - Point of sale - system
The other will be a hosted eCommerce platform
There will be a minimal interface for configuration of the service. nothing more.
Yes, Node.js is perfectly suited to making calls to external APIs. Just like everything in Node, however, the functions for making these calls are based around events, which means doing things like buffering response data as opposed to receiving a single completed response.
For example:
// get walking directions from central park to the empire state building
var http = require("http");
url = "http://maps.googleapis.com/maps/api/directions/json?origin=Central Park&destination=Empire State Building&sensor=false&mode=walking";
// get is a simple wrapper for request()
// which sets the http method to GET
var request = http.get(url, function (response) {
// data is streamed in chunks from the server
// so we have to handle the "data" event
var buffer = "",
data,
route;
response.on("data", function (chunk) {
buffer += chunk;
});
response.on("end", function (err) {
// finished transferring data
// dump the raw data
console.log(buffer);
console.log("\n");
data = JSON.parse(buffer);
route = data.routes[0];
// extract the distance and time
console.log("Walking Distance: " + route.legs[0].distance.text);
console.log("Time: " + route.legs[0].duration.text);
});
});
It may make sense to find a simple wrapper library (or write your own) if you are going to be making a lot of these calls.
Sure. The node.js API contains methods to make HTTP requests:
http.request
http.get
I assume the app you're writing is a web app. You might want to use a framework like Express to remove some of the grunt work (see also this question on node.js web frameworks).
/*Below logics covered in below sample GET API
-DB connection created in class
-common function to execute the query
-logging through bunyan library*/
const { APIResponse} = require('./../commonFun/utils');
const createlog = require('./../lib/createlog');
var obj = new DB();
//Test API
routes.get('/testapi', (req, res) => {
res.status(201).json({ message: 'API microservices test' });
});
dbObj = new DB();
routes.get('/getStore', (req, res) => {
try {
//create DB instance
const store_id = req.body.storeID;
const promiseReturnwithResult = selectQueryData('tablename', whereField, dbObj.conn);
(promiseReturnwithResult).then((result) => {
APIResponse(200, 'Data fetched successfully', result).then((result) => {
res.send(result);
});
}).catch((err) => { console.log(err); throw err; })
} catch (err) {
console.log('Exception caught in getuser API', err);
const e = new Error();
if (err.errors && err.errors.length > 0) {
e.Error = 'Exception caught in getuser API';
e.message = err.errors[0].message;
e.code = 500;
res.status(404).send(APIResponse(e.code, e.message, e.Error));
createlog.writeErrorInLog(err);
}
}
});
//create connection
"use strict"
const mysql = require("mysql");
class DB {
constructor() {
this.conn = mysql.createConnection({
host: 'localhost',
user: 'root',
password: 'pass',
database: 'db_name'
});
}
connect() {
this.conn.connect(function (err) {
if (err) {
console.error("error connecting: " + err.stack);
return;
}
console.log("connected to DBB");
});
}
//End class
}
module.exports = DB
//queryTransaction.js File
selectQueryData= (table,where,db_conn)=>{
return new Promise(function(resolve,reject){
try{
db_conn.query(`SELECT * FROM ${table} WHERE id = ${where}`,function(err,result){
if(err){
reject(err);
}else{
resolve(result);
}
});
}catch(err){
console.log(err);
}
});
}
module.exports= {selectQueryData};
//utils.js file
APIResponse = async (status, msg, data = '',error=null) => {
try {
if (status) {
return { statusCode: status, message: msg, PayLoad: data,error:error }
}
} catch (err) {
console.log('Exception caught in getuser API', err);
}
}
module.exports={
logsSetting: {
name: "USER-API",
streams: [
{
level: 'error',
path: '' // log ERROR and above to a file
}
],
},APIResponse
}
//createlogs.js File
var bunyan = require('bunyan');
const dateFormat = require('dateformat');
const {logsSetting} = require('./../commonFun/utils');
module.exports.writeErrorInLog = (customError) => {
let logConfig = {...logsSetting};
console.log('reached in writeErrorInLog',customError)
const currentDate = dateFormat(new Date(), 'yyyy-mm-dd');
const path = logConfig.streams[0].path = `${__dirname}/../log/${currentDate}error.log`;
const log = bunyan.createLogger(logConfig);
log.error(customError);
}
A more easy and useful tool is just using an API like Unirest; URest is a package in NPM that is just too easy to use jus like
app.get('/any-route', function(req, res){
unirest.get("https://rest.url.to.consume/param1/paramN")
.header("Any-Key", "XXXXXXXXXXXXXXXXXX")
.header("Accept", "text/plain")
.end(function (result) {
res.render('name-of-the-page-according-to-your-engine', {
layout: 'some-layout-if-you-want',
markup: result.body.any-property,
});
});

Categories

Resources