Can't get Braintree Client Token NodeJS - javascript

I'm trying to get a client token from the BrainTree API. I can establish a connection normally but when the code is executed the client token is always null. I've tried multiple solutions including this one here, but no luck.
The code is deployed in an Azure Function.
My Server Side Code :
module.exports = async function (context, req) {
const express = require("express");
const router = express.Router();
var braintree = require("braintree");
var clientToken;
var gateway = new braintree.BraintreeGateway({
environment: braintree.Environment.Sandbox,
merchantId: 'xxxx',
publicKey: 'xxxx',
privateKey: 'xxx'
});
context.log('about to generate a client key');
var Ctk = await gateway.clientToken.generate({}, (err, response) => {
clientToken = response.clientToken
});
var responseC = "The Client token is +" +clientToken;
context.res = {
body: responseC
};
context.log('client key generated');
}

The await keyword only works with functions that return Promise objects. While the Braintree documentation isn't 100% crystal-clear on this, the implication that's raised by switching the sample code on the linked page from "callbacks" to "Promises" is that when you specify a callback function via the second positional parameter a Promise isn't returned, thus nuking the value of using await in the first place. In this scenario, it doesn't work as you expect it and will continue to process asynchronously via the callback, which is why your clientToken isn't getting set the way you think it should.
If you're invested in using Promises all the way through, consider chaining the callback within a .then() call as the documentation prescribes. You also don't need to capture the return value of the call to generate(), as you're storing it in clientToken and not using Ctk at all.
await gateway.clientToken.generate({}).then((err, response) => {
clientToken = response.clientToken
});

I have resolved this using the following code in the end.
It looks like braintree's functions are async and therefore we need to wait for them to complete. Promisify() did the job.
module.exports = async function (context, req) {
const express = require("express");
const router = express.Router();
var app = express();
var braintree = require("braintree");
var clientToken;
var gateway = new braintree.BraintreeGateway({
environment: braintree.Environment.Sandbox,
merchantId: 'xxx',
publicKey: 'xxx',
privateKey: 'xxx'
});
const util = require('util');
const sale = util.promisify(gateway.clientToken.generate);
result = await gateway.clientToken.generate({
}).then(response => {
// pass clientToken to your front-end
clientToken = response.clientToken
});
var cToken= "client token is : " +clientToken;
context.res = {
body: cToken
};
}

Related

http server respnd with an output from an async function

I want my http respond script to respond with data from my SQL server. So I can use AJAX to update HTML with data from my SQL server. And I cant find a way to do this. I'm just learning about async and I have a feeling that if I can save the output of my async function to a global var then it will work. Any help would save my headache.
My simple Listen script is:
var test = "hello!"
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write(test);
res.end();
}).listen(8080);
and my sql code is:
const util = require('util');
var mysql = require('mysql');
var con = mysql.createConnection({
host: "XXXXX",
user: "XXXXX",
password: "XXXXX",
database: "XXX"
});
var DBresult=null;
function getdb(){
const query = util.promisify(con.query).bind(con);
(async () => {
try {
const rows = await query('SELECT * FROM mylist');
DBresult=rows;
} finally {
con.end();
}
})()
}
Do NOT use any globals or shared, higher scoped variables for your asynchronous result in a server. Never do that. That is an anti-pattern for good reason because that can create intermittent concurrency problems because more than one request can be in process at the same time on your server so these would cause conflicting access to those variables, creating intermittent, very-hard-to-debug problems. I repeat again, NEVER.
You didn't describe an exact situation you are trying to write code for, but here's an example.
Instead, you use the result inside the context that it arrives from your asynchronous call. If you can use await, that generally makes the coding cleaner.
Here's a simple example:
const con = mysql.createConnection({
host: "XXXXX",
user: "XXXXX",
password: "XXXXX",
database: "XXX"
});
const query = util.promisify(con.query).bind(con);
http.createServer(async function(req, res) {
if (req.path === "/query" && req.method === "GET") {
try {
const rows = await query('SELECT * FROM mylist');
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(rows));
} catch(e) {
console.log(e);
res.statusCode = 500;
res.end();
}
} else {
// some other respone
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write("hello");
res.end();
}
}).listen(8080);
Things to note here:
Checking both path and method before handling the request.
Making callback function async so it can use await.
Making sure any promise rejection from await is caught by try/catch and an error response is sent if there's an error.
Sending result as JSON and setting appropriate content-type.
You may be using the plain http module as a learning experience, but you will very quickly find that using the simple Express framework will save you lots of programming time and make things lots easier.
If you want to use async functions, it would be something like this, take care of "async" in function for the createServer
var http = require('http');
var server = http.createServer(async (req, res) => {
async function mgetdata() {
// Async code goes here
return 'Hello, world!';
}
// Wait for the async function to complete and get its return value
const response = await mgetdata();
// Send the response
res.end(response);
});

async.waterfall not acting synchronously

I'm trying to write a header of an MD5 hash token using crypto then return it back as a response. For some reason, it isn't actually running synchronously. I know JS is an asynchronous language, and that's really the only part I'm struggling with right now. Any help would be appreciated.
This is what I have so far:
const crypto = require('crypto');
const bodyParser = require('body-parser');
const formidable = require('formidable');
const async = require('async')
app.post('/pushurl/auth', (req, res) =>
var data = req.body.form1data1 + '§' + req.body.form1data2
async.waterfall([
function(callback) {
var token = crypto.createHash('md5').update(data).digest("hex");
callback(null, token);
},
function(token, callback) {
res.writeHead(301,
{Location: '/dashboard?token=' + token}
);
callback(null)
},
function(callback) {
res.end();
callback(null)
}
]);
}
});
Output:
Uncaught Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
<node_internals>/internal/errors.js:256
No debugger available, can not send 'variables'
Process exited with code 1
JavaScript is an asynchronous language, yes, but it can also do synchronous tasks very well. In your case, you don't need to do any async expect if you're dealing with promises.
If you write your code like in the example below it will just execute from top to bottom.
But the error (probably) occurred because you forgot to add an opening curly brace to your app.post callback, which results in the data var being immediately returned because of an implied return statement () => (implied), () => {} (explicit).
const crypto = require('crypto');
const bodyParser = require('body-parser');
const formidable = require('formidable');
app.post('/pushurl/auth', (req, res) => {
const data = req.body.form1data1 + '§' + req.body.form1data2;
const token = crypto.createHash('md5').update(data).digest("hex");
res.writeHead(301, {
Location: '/dashboard?token=' + token
});
res.end();
});

Javascript: exporting objects initialized asynchronously [duplicate]

I'm kinda new to module creation and was wondering about module.exports and waiting for async functions (like a mongo connect function for example) to complete and exporting the result. The variables get properly defined using async/await in the module, but when trying to log them by requiring the module, they show up as undefined. If someone could point me in the right direction, that'd be great. Here's the code I've got so far:
// module.js
const MongoClient = require('mongodb').MongoClient
const mongo_host = '127.0.0.1'
const mongo_db = 'test'
const mongo_port = '27017';
(async module => {
var client, db
var url = `mongodb://${mongo_host}:${mongo_port}/${mongo_db}`
try {
// Use connect method to connect to the Server
client = await MongoClient.connect(url, {
useNewUrlParser: true
})
db = client.db(mongo_db)
} catch (err) {
console.error(err)
} finally {
// Exporting mongo just to test things
console.log(client) // Just to test things I tried logging the client here and it works. It doesn't show 'undefined' like test.js does when trying to console.log it from there
module.exports = {
client,
db
}
}
})(module)
And here's the js that requires the module
// test.js
const {client} = require('./module')
console.log(client) // Logs 'undefined'
I'm fairly familiar with js and am still actively learning and looking into things like async/await and like features, but yeah... I can't really figure that one out
You have to export synchronously, so its impossible to export client and db directly. However you could export a Promise that resolves to client and db:
module.exports = (async function() {
const client = await MongoClient.connect(url, {
useNewUrlParser: true
});
const db = client.db(mongo_db);
return { client, db };
})();
So then you can import it as:
const {client, db} = await require("yourmodule");
(that has to be in an async function itself)
PS: console.error(err) is not a proper error handler, if you cant handle the error just crash
the solution provided above by #Jonas Wilms is working but requires to call requires in an async function each time we want to reuse the connection. an alternative way is to use a callback function to return the mongoDB client object.
mongo.js:
const MongoClient = require('mongodb').MongoClient;
const uri = "mongodb+srv://<user>:<pwd>#<host and port>?retryWrites=true";
const mongoClient = async function(cb) {
const client = await MongoClient.connect(uri, {
useNewUrlParser: true
});
cb(client);
};
module.exports = {mongoClient}
then we can use mongoClient method in a diffrent file(express route or any other js file).
app.js:
var client;
const mongo = require('path to mongo.js');
mongo.mongoClient((connection) => {
client = connection;
});
//declare express app and listen....
//simple post reuest to store a student..
app.post('/', async (req, res, next) => {
const newStudent = {
name: req.body.name,
description: req.body.description,
studentId: req.body.studetId,
image: req.body.image
};
try
{
await client.db('university').collection('students').insertOne({newStudent});
}
catch(err)
{
console.log(err);
return res.status(500).json({ error: err});
}
return res.status(201).json({ message: 'Student added'});
};

How can I solve the problem with forwarding messages?

I'm created a chat-bot using 'botact' library, but
when I'm trying to verificate my bot on vk-community API working page I receive an error in 'Windows PowerShell' (Here I started the server for bot):
TypeError: Cannot read property 'fwd_messages' of undefined
at Botact.getLastMessage (C:\Users\whoami\Desktop\Bot-test\node_modules\botact\lib\utils\getLastMessage.js:2:11)
at Botact.module.exports (C:\Users\whoami\Desktop\Bot-test\node_modules\botact\lib\methods\listen.js:29:28).
The file 'getLastMessage.js' contains this code:
const getLastMessage = (msg) => {
if (msg.fwd_messages && msg.fwd_messages.length) {
return getLastMessage(msg.fwd_messages[0])
}
return msg
}
module.exports = getLastMessage
So I don't know much about botact but according to the code when you are hitting the / route, you need to pass a body containing an object property.
Now as this is bot framework for vk bots maybe it automatically sends the request body. You can make sure by logging the request body.
server.post('/', async (req,res)=>{
console.dir(req.body);
await bot.listen(req, res);
});
/lib/methods/listen.js:
const { type, secret, object, group_id } = framework === 'koa'
? args[0].request.body
: args[0].body
...
...
...
const { events, middlewares } = actions
const forwarded = this.getLastMessage(object)
Now, when you do bot.listen express passes req as first argument. and { type, secret, object, group_id } these fields get distructured from the req.body.
And then object is getting passed to the getLastMessage function.
So for the request body in minimum you would need
{ "object": {} }
Here is the 200 OK output that I got after added that to the request body from Postman
POC Code:
const express = require("express");
const bodyParser = require("body-parser");
const { Botact } = require("botact");
const server = express();
const bot = new Botact({
token: "token_for_my_group_i_just_hided_it",
confirmation: "code_for_my_group_i_just_hided_it"
});
server.use(bodyParser.json());
server.post("/",bot.listen);
server.listen(8080);

Access mongodb+nodjs from javascript?

I'm running a server with nodejs+mongodb:
let MongoClient = require('mongodb').MongoClient.connect("mongodb://localhost:27017/mydb", { useNewUrlParser: true } ),
(async () =>{
let client;
try {
client = await MongoClient;
...
I'm creating some data-visualizations and I need a simple way to access my backend data from javascript, is this possible? Ideally I would like full access.
You have to build a bridge, e.g. using a REST API:
// server.js
// npm install express, body-parser, mongodb
const app = require("express")();
const bodyParser = require("body-parser");
const db = require("mongodb").MongoClient.connect(/*...*/);
app.use(bodyParser.json());
app.post("/findOne", async (req, res) => {
try {
const connection = await db;
const result = await connection.findOne(req.body);
if(!result) throw new Error("Not found!");
res.status(200).json(result);
} catch(error) {
res.status(500).json(error);
}
});
// ... all those other methods ...
app.listen(80);
That way you can easily connect to it on the client:
// client.js
function findOne(query) {
const result = await fetch("/findOne/", {
method: "POST",
body: JSON.stringify(query),
headers:{
'Content-Type': 'application/json'
}
});
if(!result.ok) throw await result.json();
return await result.json();
}
Note: I hope you are aware that you also allow some strangers to play with your database if you do not validate the requests properly / add authentication.
For security purposes you should never do this, but hypothetically you could make an AJAX endpoint or WebSockets server on the node application that passes the input straight to mongoDB and takes the output straight back to the client.
It would be a much better practice to write a simple API using AJAX requests or WS to prevent the user from compromising your database.

Categories

Resources