Using Node.js to connect to a REST API - javascript

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

Related

Opening Web Socket connection from app.get (Express)

I am running the Bitfinex Websocket connection from node.js server using express.
I have an API endpoint so that I ask for the specific book from the link (e.g http://localhost:4000/BTC-USD/buy/100)
The problem is that when I try to make the connection from the app.get the websocket doesn't respond
It only responds from outside. The problem is that, that way I cant pass the parameter so I can establish the proper connection. The code I can't perform
app.get("/:pair/:type/:amount", async (req,res) => {
let { pair, type, amount } = req.params;
try {
wsConnection(pair);
wsMessageHandler()
const result = await simulateEffectivePrice({ pair, type, amount })
res.send({ "effectivePrice" : result })
} catch (error) {
res.send({"error" : error.message})
}
})
The code that works:
wsConnection();
wsMessageHandler()
app.get("/:pair/:type/:amount", async (req,res) => {
let { pair, type, amount } = req.params
try {
// if (type !== "buy" || type !== "sell") throw new Error ("wrong type input")
const result = await simulateEffectivePrice({pair,type,amount})
res.send({ "effectivePrice" : result })
} catch (error) {
res.send({"error" : error.message})
}
})
The wsConnection functions is this, (it requires the book you want to receive information from)
const wsConnection = async () => {
let msg = JSON.stringify({
event: 'subscribe',
channel: 'book',
symbol: 'tBTCUSD',
// len: "25"
})
try {
w.on('open', () => {
w.send(JSON.stringify({ event: 'conf', flags: 65536 + 131072 }))
w.send(msg)
})
} catch (error) {
throw new Error("BUILD CUSTOM ERROR")
}
}
"symbol" would need to be the parameter specified on the endpoint by the user
Thank you very much

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

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

Using Graph API not able to get events for particular date using filter param

var authEndpoint = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?";
var redirectUri = "http://localhost:8080";
var appId = "SomethingSomething";
var scopes = "openid profile User.Read Mail.Read Calendars.Read";
function getUserEvents(callback) {
getAccessToken(function(accessToken) {
if (accessToken) {
// Create a Graph client
var client = MicrosoftGraph.Client.init({
authProvider: done => {
// Just return the token
done(null, accessToken);
}
});
// Get the 10 newest events
client
.api("/me/events")
.filter("startDateTime='2018-03-01'&endDateTime='2018-03-31'")
.select("subject,start,end,createdDateTime")
.orderby("createdDateTime DESC")
.get((err, res) => {
if (err) {
callback(null, err);
} else {
callback(res.value);
}
});
} else {
var error = { responseText: "Could not retrieve access token" };
callback(null, error);
}
});
}
This is the request that my program sends out:
https://graph.microsoft.com/v1.0/me/events?$filter=2018-07-15T01:00:00&$select=subject,start,end,createdDateTime&$orderby=createdDateTime%20DESC
400 (Bad Request)
You're attempting to filter the /events endpoint using properties that don't exist in the event object (startDateTime and endDateTime). You're also passing a = in the filter clause instead of eq.
The /calendarView endpoint does have startDateTime and endDateTime parameters, but these are query params unto themselves (not part of a filter clause). I suspect this is the operation you're actually looking for:
client
.api("/me/calendarview")
.query({
startdatetime: "2018-03-01T00:00:00.0000000",
enddatetime: "2018-03-31T23:00:00.0000000"
})
.select("subject,start,end,createdDateTime")
.orderby("createdDateTime DESC")
.get((err, res) => {
if (err) {
callback(null, err);
} else {
callback(res.value);
}
});

How to return a documentDB document with Azure functions?

I created an azure function as well as a documentDB database with a users collection, however, I am stuck at connecting the two of them to each other. I want to just send a username and the function queries the database then returns the user with that unique username.
I am using node js. Any ideas?
Thanks
First of all, you'd need to install the documentdb module via npm. Use the following command:
npm install documentdb --save
After that, you've finished setting up. Now you can start writing some code to query the collection in the database. The following is an example of querying a family collection with Azure HTTP-trigger function.
The folder structure:
node_modules/
.gitignore
config.js
function.json
index.js
package.json
CONFIG.JS
var config = {}
config.endpoint = "https://<documentdb name>.documents.azure.com:443/";
config.primaryKey = "<primary key>";
config.database = {
"id": "FamilyDB"
};
config.collection = {
"id": "FamilyColl"
};
module.exports = config;
INDEX.JS
var documentClient = require("documentdb").DocumentClient;
var config = require("./config");
var databaseUrl = `dbs/${config.database.id}`;
var collectionUrl = `${databaseUrl}/colls/${config.collection.id}`;
var client = new documentClient(config.endpoint, { "masterKey": config.primaryKey });
module.exports = function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
if (req.query.name || (req.body && req.body.name)) {
var name = req.query.name || req.body.name;
queryCollectionByName(name).then((result) => {
context.log('result: ', result);
res = {
body: "Result: " + JSON.stringify(result)
};
context.done(null, res);
}, (err) => {
context.log('error: ', err);
res = {
body: "Error: " + JSON.stringify(err)
};
context.done(null, res);
});
}
else {
res = {
status: 400,
body: "Please pass a name on the query string or in the request body"
};
context.done(null, res);
}
};
function queryCollectionByName(name) {
return new Promise((resolve, reject) => {
client.queryDocuments(
collectionUrl,
`SELECT VALUE r.children FROM root r WHERE r.lastName = "${name}"`
).toArray((err, results) => {
if (err) reject(err)
else {
resolve(results);
}
});
});
};
Tested result:
For more details, please refer to https://learn.microsoft.com/en-us/azure/documentdb/documentdb-nodejs-get-started.

ssh2 connect to multiple server and get the output nodejs

I am using ssh2 nodejs module to connect to a UNIX application and run a script and it is successful.
Now i want to connect to multiple servers one by one and get the output and store it.
When i try using a for loop to pass the servers one by one from a json as input to the ssh2 the for loop completes much faster than the block which is supposed to get the output from the server.
This is also causing me handshake error.
Kindly help
Here is the code
inc_cron.schedule("*/20 * * * * *", function(id) {
});
//inc_cron.js
var cronFunction = function(inputStr) {
if(appNames['applications'].length>0){
for (i = 0; i < appNames["applications"].length; i++) {
getDataFromServer(appNames["applications"][i].Name,appNames["applications"][i].hostname, appNames["applications"][i].username, appNames["applications"][i].password, appNames["applications"][i].log_path, function(err, data) {
if(err) {
logger.info("Error is in cronFunction = ", err);
} else if(data) {
output_data +=data;
} ssh.close_second();
});
}
}
}
var getDataFromServer = function(Name,hostname, username, password, log_path, cb) {
ssh.close_second();
ssh.connect_second({
host: hostname,
username: username,
password: password
}, function(err) {
if(err) {
logger.error('Err: ', err);
} else {
ssh.sftp("",'grep -o "ERROR" '+log_path+'.log.'+yr+'-'+mnth+'-* | wc -l', function(err, data) {
cb(err, data);
}); } }); }
//connect.js
SSHConnection.prototype.sftp = function(type, path, cb) {
var self = this;
var log_data = '';
self.connection2.exec(path +' ' + type, { pty: true }, function(err, stream) {
if (err) {
logger.log('SECOND :: exec error: ' + err);
}
stream.on('end', function() {
self.connection2.end(); // close parent (and this) connection
}).on('data', function(data) {
logger.info(data.toString());
});
});
};
Without watch your code, be sure to handle correctly the async issue with ssh2... use a promise factory.
One way to do this is to use es7 async await. For this you have to rewrite your getDataFromServer function to return a promise:
var getDataFromServer = function(Name,hostname, username, password, log_path, cb) {
return new Promise(function(resolve,reject){
ssh.close_second();
sh.connect_second({
host: hostname,
username: username,
password: password
},function(err) {
if(err){
reject(err)
}else{
ssh.sftp("",'grep -o "ERROR" '+log_path+'.log.'+yr+'-'+mnth+'-* | wc -l', function(err, data) {
if(err){
reject(err)
}else{
resolve(data)
}
})
}
})
})
}
now you can rewrite your cron function to be an async function.
var cronFunction = async function(inputStr) {
if(appNames['applications'].length>0){
for (i = 0; i < appNames["applications"].length; i++) {
try{
output_data + = await getDataFromServer(appNames["applications"][i].Name,appNames["applications"][i].hostname, appNames["applications"][i].username, appNames["applications"][i].password, appNames["applications"][i].log_path)
}catch(err){
logger.info("Error is in cronFunction = ", err);
}
ssh.close_second();
}
}
}
async await enables you to write async code in syncronous coding style.
However async await is currently (node 7.*) hidden behind a flag (--harmony-async-await). this feature will be enable by default in the upcomming node release (8.0.0) in April 2017.
so to start your app you currently have to use
node --harmony-async-await yourapp.js
P.S.: This code is currently untested and most probably contains bugs .. but you get the idea.

Categories

Resources