How to use util.promisify to promisify a function in NodeJs? - javascript

I am trying to convert a Callback function into a Promise,
I'm using util.promisify for this and following is my working code vs the new non working one.
Working code, using Node Callback style -
let AWS = require(aws-sdk');
let moduleName = process.env.Module;
module.exports = {
getConstants
};
function getConstants (callback) {
let client = new AWS.SSM({
region: "us-east-1"
});
let smName = "/somePath";
let params = {
Names: [smName]
};
client.getParameters(params, function (err, data) {
if (err) {
console.log(err, err.stack);
callback(err, null);
}
else{
console.log(METHOD_TAG,'Parameter Store call successful!');
let constantVariables = data.Parameters[0].Value;
callback(null, constantVariables);
}
});
}
New Non working code -
let AWS = require('aws-sdk');
let util = require('util');
let moduleName = process.env.Module;
module.exports.getConstants = async () => {
let client = new AWS.SSM({
region: "us-east-1"
});
let smName = "/somePath";
let params = {
Names: [smName]
};
let parameterStore = util.promisify(client.getParameters).bind(client);
let response = await parameterStore.getParameters(params);
let constantVariables = response.Parameters[0].Value;
return constantVariables;
};
I am getting the following error -
TypeError: parameterStore.getParameters is not a function"
when trying to promisify the getParameters function of the AWS.SSM client.
What am I doing wrong, what should I change?
Reference -
https://medium.com/#suyashmohan/util-promisify-in-node-js-v8-d07ef4ea8c53
https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SSM.html#getParameters-property

Related

Mongoose data Writing issue in Javascript

Just started with a javascript couple of days back. I am trying to use MongoDB with mongoose to write the data but it is not writing even though the connection is established.
I would really appreciate it if you can help me point out what I am missing here.
dbtest.js - module to create connection
require("dotenv").config();
const mongoose = require("mongoose");
const Block = require("./model/blockSchema");
const connectDB = async () => {
try {
await mongoose.connect(process.env.DATABASE_URI, {
useUnifiedTopology: true,
useNewUrlParser: true,
});
console.log("CONNECTED to MONGODB DATABASE");
} catch (err) {
console.error(err);
}
};
module.exports = connectDB;
blockchain.js
Even though I have verified the connection before calling the main method, it looks like the connection is not available to class methods.
require("dotenv").config();
const { hash256 } = require("../util/util");
const block = require("./block");
const blockchain = require("./blockHeader");
const Block = require("../database/model/blockSchema");
const { mongoose } = require("mongoose");
const connect = require("../database/dbtest");
VERSION = 1;
const ZERO_HASH = String("0").padStart(64, "0");
// Create connection
connect();
class Blockchain {
GenesisBlock() {
try {
const BlockHeight = 0;
const prevBlockHash = ZERO_HASH;
this.addBlock(BlockHeight, prevBlockHash);
} catch (err) {
console.log(`Error in Genesis Blockchain Function \n ${err}`);
}
}
addBlock(BlockHeight, prevBlockHash) {
let timestamp = Date.now();
let Transaction = `Codies Alert sent ${BlockHeight} to Anni`;
let merkleRoot = hash256(Transaction);
let bits = "ffff001f";
let blockHeader = new blockchain.BlockHeader(
VERSION,
prevBlockHash,
merkleRoot,
timestamp,
bits
);
//Mine a Block
blockHeader.mine();
// Create Schema Instance to Write the data
let BlockObj = new Block({
Height: BlockHeight,
BlockSize: 1,
blockHeader: {
version: 1,
prevBlockHash: "00000",
timestamp: timestamp,
bits: bits,
nonce: blockHeader.nonce,
blockHash: blockHeader.blockhash,
},
TxCount: 1,
Transactions: Transaction,
});
// Mongoose Schema, Write data
BlockObj.save((err) => {
if (err) return console.log(`Error while Writing the Block ${err}`);
console.log(`Block Written Successfully!!!!!!!`);
});
this.chain = new block.Block(BlockHeight, 1, blockHeader, 1, Transaction);
console.log(BlockObj);
}
// Main Function to trigger the process
main() {
this.chain = "";
this.GenesisBlock();
while (true) {
let lastBlock = this.chain;
let Blockheight = lastBlock.Height + 1;
let prevBlockHash = lastBlock.BlockHeader.blockhash;
this.addBlock(Blockheight, prevBlockHash);
}
}
}
mongoose.connection.once("open", async () => {
console.log("Connection Verified and ready to write data");
// Create an instance and call the main method
const blockchain = new Blockchain();
blockchain.main();
});
Issue was due to async/await. Here is the updated code that works.
require("dotenv").config();
const { hash256 } = require("../util/util");
const block = require("./block");
const blockchain = require("./blockHeader");
const Block = require("../database/model/blockSchema");
const connect = require("../database/dbtest");
const getLastBlock = require("../database/read");
VERSION = 1;
const ZERO_HASH = String("0").padStart(64, "0");
let mongoose = "";
class Blockchain {
async GenesisBlock() {
try {
console.log(mongoose.connection.readyState);
const BlockHeight = 0;
const prevBlockHash = ZERO_HASH;
await this.addBlock(BlockHeight, prevBlockHash);
} catch (err) {
console.log(`Error in Genesis Blockchain Function \n ${err}`);
}
}
async addBlock(BlockHeight, prevBlockHash) {
let timestamp = Date.now();
let Transaction = `Codies Alert sent ${BlockHeight} to Anni Maan`;
let merkleRoot = hash256(Transaction);
let bits = "ffff001f";
let blockHeader = new blockchain.BlockHeader(
VERSION,
prevBlockHash,
merkleRoot,
timestamp,
bits
);
blockHeader.mine();
let BlockObj = {
Height: BlockHeight,
BlockSize: 1,
blockHeader: {
version: 1,
prevBlockHash: blockHeader.prevBlockhash,
merkleroot: merkleRoot,
timestamp: timestamp,
bits: bits,
nonce: blockHeader.nonce,
blockhash: blockHeader.blockhash,
},
TxCount: 1,
Transactions: Transaction,
};
// Mongoose Schema, Write data
try {
await new Block(BlockObj).save();
console.log(BlockObj);
console.log("Block Written Successfully");
this.chain = new block.Block(BlockHeight, 1, blockHeader, 1, Transaction);
} catch (err) {
console.log(`Error in addBlock Function \n ${err}`);
}
}
// Main Function to trigger the process
async main() {
const lastBlock = await getLastBlock.main(true);
console.log(lastBlock[0]);
this.chain = lastBlock[0];
if (!this.chain) {
await this.GenesisBlock();
}
while (true) {
console.log(mongoose.connection.readyState);
let lastBlock = this.chain;
let Blockheight = lastBlock.Height + 1;
let prevBlockHash = lastBlock.blockHeader.blockhash;
await this.addBlock(Blockheight, prevBlockHash);
}
}
}
const createConnection = async () => {
try {
mongoose = await connect();
const blockchain = new Blockchain();
blockchain.main();
} catch (err) {
console.log("Error while con", err);
}
};
createConnection();
The issue in your code is due to the asynchronous programming, whenever you make a db call it is an asynchronous request and you will need to use async-await or Promises to make it work. In your previous code you haven't used async await thats why your data is not getting written into the db.
You can learn about async await here link and about promises here.
Please go through it, promises are the core concept of js and you will definitely need it if you are using node js.
Also try to learn about synchronous and asynchronous from here, these are really necessary and base of node js.
All these db calls needs to call with promises or async await to make it work.

How to call a javascript function inside another function in node js

I have a file index.js as below. Where I am trying to call a async function getConn in other function createThumbnails. But I am getting the error as "failed to connect to DEDC: 1433 - self signed certificate" in the catch block.
const sharp = require('sharp');
const sql = require('mssql')
// CONNECTION CONFIGURATION OF BASE DB
async function getConn() {
try {
const config = {
user: 'sa_user',
password: '*******',
server: 'DEDC',
database: 'DEMO_BASE'
}
const pool = await new sql.ConnectionPool(config)
const req=await pool.connect()
const conn = await req.request()
return conn;
} catch (err) {
return err;
}
};
const createThumbnails = async() => {
try{
var conn = await getConn();
const query = `exec DBBASE.get_client_info`
var clientusers = await conn.query(query);
} catch (err) {
return err;
}
}
createThumbnails()
How do I exactly call the function getConn inside createThumbnails. Please help. Thanks in advance
It's because you are using variable with the same name as the function.
Try different name:
var conn = await getConn();
const query = `exec DBBASE.get_client_info`
var clientusers = await conn.query(query);
You encounter what called hoisting. Kyle Simpson has a great explaination on this topic
var getConn = await getConn();
which means getConn will be initialized first, before assignment, which equivalents to
var getConn // initialized
getConn = await getConn() // assignment
Then turned out that you got the error
Solution here is to store it in a different variable name, like
var conn = await getConn();
async function getConn() {
return {
query: async () => {
console.log("query called");
},
};
}
const createThumbnails = async () => {
try {
var conn = await getConn();
const query = `exec DBBASE.get_client_info`;
var clientusers = await conn.query(query);
} catch (err) {
console.log(err);
}
};
createThumbnails();
We need to use trustServerCertificate: true in DB configuration i.e in const config

How to pass object from one file to another in javascript?

I have node js server file (index.js) and client file (orderlist.js)
In index.js i am getting promise object , like that
function returnOrderArray() {
var i = 0;
const promise = new Promise((resolve, reject) => {
connection.query('SELECT * FROM orders', function(error, results) {
while (i < results.length) {
order.id[i] = results[i].id;
order.wavetype[i] = results[i].wavetype;
order.color[i] = results[i].color;
order.thick[i] = results[i].thick;
order.readydate[i] = results[i].readydate;
order.createdate[i] = results[i].createdate;
order.manager[i] = results[i].manager;
i++;
}
resolve(order);
// console.log(order);
});
});
return promise;
}
then i want to pass it to other js file.
I tried to do that with module.exports
app.get('/orderlist', checkUserSession, async function(request, response) {
returnOrderArray().catch(error => console.log(error)).then((() => {
module.exports.order = order;
response.render("orderlist.ejs", { username: request.session.username });
})).catch(error => console.log(error));
});
and then import it in orderlist.js
var ind = require('../../index')
function asd() {
alert(ind.order);
}
but it seems not to work.
What am i doing wrong , and what's the best way to pass objects to other files in js?
oh , and file architecture
filearch
You need to export your module like so: module.exports = returnOrderArray
try this,
orderlist.js
const returnOrderArray = () => {...some code..}
module.exports = returnOrderArray
index.js
const returnOrderArray = require('./path/to/orderlist.js')
const run = async() => {
const orderlist = await returnOrderArray() // use await or then as you prefer
}
run()
async_await link if curious!
Hope this will work :)

Return value to variable from function

I am looking to return a value to a varible when I call the function in nodejs.
The output I am looking for is "Calling From Glasgow to Euston"
The output I am getting is "Calling From undefined to undefined"
Code is the following.
function trainstation(stx, callBack) {
MongoClient.connect(ttdb, function(err, db) {
if (err) throw err;
var dbo = db.db("ttdb");
var collection = dbo.collection("tlc");
var find = collection.find( { "Stanox" : stx } );
find.toArray(function(err, result) {
if (err) throw err;
db.close();
return callBack(result);
});
});
};
function gettrain(){
var ts1 = trainstation(9531, function(x){
return x[0]['Station Name'];
});
var ts2 = trainstation(31033, function(x){
return x[0]['Station Name'];
});
console.log("Calling From", ts1, "to", ts2);
};
gettrain();
Thanks :)
I don't use the MongoDB package and I don't have MongoDB up & running right now to test this, so I've written this code purely based on a quick read of the reference documentation. Perhaps you can test this and we'll fix any minor issues. Copy this code to a new source file and test it.
What I've done is to take advantage of the MongoDB package's promise features. You can see that the code is more linear and simpler to follow.
const MongoClient = require('mongodb').MongoClient;
const ttdb = 'mongodb://localhost:27017'; // or your DB URL
const trainstation = async (Stanox) => {
const client = MongoClient(ttdb);
await client.connect();
const dbo = client.db("ttdb");
const collection = dbo.collection("tlc");
const result = await collection.find({Stanox}).toArray();
client.close();
return result;
};
const gettrain = async () => {
const ts1 = await trainstation(9531);
const ts2 = await trainstation(31033);
const sn1 = ts1[0]['Station Name'];
const sn2 = ts2[0]['Station Name'];
console.log("Calling From", sn1, "to", sn2);
};
gettrain();

Exporting data in a node file after it is returned from an API call to AWS Secrets Manager

Background
I am storing the database information for a RDS in AWS in the secrets manager. I am using the AWS-SDK to retrieve the password and other data so I can create a secrets object at run time. When I try and create this object and then export it, the object that is exported is always lacking the data that I expect to be returned from the aws-sdk.
What I Have Tried -
I have tried using async await but it is still exporting the object before all of the data is correctly populated.
Example
const AWS = require('aws-sdk');
const region = 'us-west-2';
const secretName = 'example/example/example';
let secrets = {
username: '',
password: '',
host: '',
port: '',
database: '',
email: 'example#example.com',
emailPassword: 'SomePassword'
};
const client = new AWS.SecretsManager({
region: region
});
client.getSecretValue({ SecretId: secretName }, async (err, data) => {
if (err) {
throw err;
} else {
const res = await JSON.parse(data.SecretString);
secrets.username = res.username;
secrets.password = res.password;
secrets.host = res.host;
secrets.port = res.port;
secrets.database = res.database;
}
});
module.exports = secrets;
Question
The obvious problem here is not creating the promise correctly but I am not sure why my attempts are completing the promises after the file gets exported. If I console.log(secrets) in another file in some cases it will output the object missing data then show the data returned by the promise a few seconds later after when I console.log(secrets) inside of the function.
What is the proper way to build this object secrets and export it once the data is returned from AWS and added to the object secrets?
According to the docs, the second argument to getSecretValue is a callback function, so there's no need to use async/await since async/await is meant to work with promises.
Removing async/await should work.
client.getSecretValue({ SecretId: secretName }, (err, data) => {
if (err) {
throw err;
} else {
const res = JSON.parse(data.SecretString);
secrets.username = res.username;
secrets.password = res.password;
secrets.host = res.host;
secrets.port = res.port;
secrets.database = res.database;
}
});
However, you're exporting the secrets object synchronously, and its properties are getting set asynchronously.
Instead, you can return a promise for your other modules to consume.
const AWS = require('aws-sdk');
const region = 'us-west-2';
const secretName = 'example/example/example';
let secrets = {
email: 'example#example.com',
emailPassword: 'SomePassword'
};
const client = new AWS.SecretsManager({
region: region
});
const promise = new Promise((resolve, reject) => {
client.getSecretValue({ SecretId: secretName }, async (err, data) => {
if (err) {
reject(err);
} else {
const res = await JSON.parse(data.SecretString);
secrets.username = res.username;
secrets.password = res.password;
secrets.host = res.host;
secrets.port = res.port;
secrets.database = res.database;
resolve(secrets);
}
});
})
module.exports = promise;
Then, in some other module that consumes this one, you can use async/await since we now have a promise.
import {promise} from "./this-module";
(async () => {
const secrets = await promise;
console.log(secrets);
})();
Update
I'm not sure if this will work, but it's worth a shot. Here, set module.exports only after secrets is set. If this doesn't work, then I would ask a new question on StackOverflow about how to export resolved promises with CommonJS (which is the module format that you're using).
const AWS = require('aws-sdk');
const region = 'us-west-2';
const secretName = 'example/example/example';
let secrets = {
email: 'example#example.com',
emailPassword: 'SomePassword'
};
const client = new AWS.SecretsManager({
region: region
});
const promise = new Promise((resolve, reject) => {
client.getSecretValue({ SecretId: secretName }, async (err, data) => {
if (err) {
reject(err);
} else {
const res = await JSON.parse(data.SecretString);
secrets.username = res.username;
secrets.password = res.password;
secrets.host = res.host;
secrets.port = res.port;
secrets.database = res.database;
resolve(secrets);
}
});
});
(async () => {
module.exports = await promise;
})();
client.getSecretValue({ SecretId: secretName }).subscribe(data=>{
const res =JSON.parse(data.SecretString);
secrets.username = res.username;
secrets.password = res.password;
secrets.host = res.host;
secrets.port = res.port;
secrets.database = res.database;
});

Categories

Resources