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
};
}
I have installed mongoose using npm install mongoose .But when i try to run the js file its not connecting.
see my code below.
const c = require('config')
const express= require('express')
const app= express()
const port=3000
const mongoose = require('mongoose')
const url = "mongodb+srv://mongouser:mongouser#cluster0.jpdno.mongodb.net/myFirstDatabase?retryWrites=true&w=majority"
const connectdb = async () => {
await mongoose.connect(url)
console.log('db connected')
}
app.listen(port,() => console.log("listening..."))
I am not getting any errors but after listening.. nothing is showing.
I am new to this please help me.
You are on the right path. To check whether you successfully connected to database use:
mongoose.connection.on('connected', () => { console.log('Successfully connected to database' });
Also you want to return your connection so you could use it later for database manipulation. It should look like this:
const connectdb = async () => {
await mongoose.connect(url);
return mongoose.connection; // Please note that you are returning reference
}
Last notes, I believe async/await is redundant when dealing with mongoose inside Node.js and you should probably want to include some option argument on your connect method:
mongoose.connect(url, {useNewUrlParser: true, useUnifiedTopology: true} );
Now you should be good to go!
I try to make upload to google cloud storage use nodejs , and I get some error
This is the code
const express = require("express");
const app = express();
app.use(express.json());
// Imports the Google Cloud client library
const { Storage } = require("#google-cloud/storage");
const storage = new Storage({
keyFilename: "jerk-70c86hks6f0c.json",
projectId: "jerk",
});
const bucketName = "mystorage";
module.exports = {
upload: (myfile, videoid) => {
return (await storage.bucket(bucketName).upload(myfile.path, {
gzip: true,
destination: "kids/video/"+{videoid}+".mp4",
metadata: {
cacheControl: "public, max-age=31536000",
},
}));
},
};
This is the result
return (await storage.bucket(bucketName).upload(myfile.path, {
^^^^^^^
SyntaxError: Unexpected identifier
Can you guys explain to me why error ? , thank you :D
The error that you are getting is because it didn't expect storage to be there. The error is due to await. You only use await in an async function.
Either make your function async or remove that await.
Here is an example:
async function myAsyncFunction() {
let result = await lengthyFunction();
console.log(result);
}
myAsyncFunction();
Also here you can see an example in the documentation where the upload is not being called in an async way since it is not inside of an async function
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();
});
This seems like a straightforward google, but I can't seem to find the answer...
Can you pass in ES6 ES7 async functions to the Express router?
Example:
var express = require('express');
var app = express();
app.get('/', async function(req, res){
// some await stuff
res.send('hello world');
});
If not, can you point me in the right direction on how to handle this problem ES7 style? Or do I just have to use promises?
Thanks!
May be you didn't found results because async/await is an ES7 not ES6 feature, it is available in node >= 7.6.
Your code will work in node.
I have tested the following code
var express = require('express');
var app = express();
async function wait (ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms)
});
}
app.get('/', async function(req, res){
console.log('before wait', new Date());
await wait(5 * 1000);
console.log('after wait', new Date())
res.send('hello world');
});
app.listen(3000, err => console.log(err ? "Error listening" : "Listening"))
And voila
MacJamal:messialltimegoals dev$ node test.js
Listening undefined
before wait 2017-06-28T22:32:34.829Z
after wait 2017-06-28T22:32:39.852Z
^C
Basicaly you got it, you have to async a function in order to await on a promise inside its code.
This is not supported in node LTS v6, so may be use babel to transpile code.
Hope this helps.
Update
Since ExpressJs 5, async functions are supported, and throw errors as expected
Starting with Express 5, route handlers and middleware that return a Promise will call next(value) automatically when they reject or throw an error
source
In Express 4 or less, it sort of works, but not really
While it seems to work, it stops handling errors thrown inside the async function, and as a result, if an error is not handled, the server never responds and the client keeps waiting until it timeout.
The correct behavior should be to respond with a 500 status code.
Solutions
express-promise-router
const router = require('express-promise-router')();
// Use it like a normal router, it will handle async functions
express-asyncify
const asyncify = require('express-asyncify')
To fix routes set in the app object
Replace var app = express(); with
var app = asyncify(express());
To fix routes set in router objects
Replace var router = express.Router(); with
var router = asyncify(express.Router());
Note
You only need to apply the asyncify function in the objects where you set the routes directly
https://www.npmjs.com/package/express-asyncify
I think you can't do it directly because exceptions are not caught and the function won't return if one is thrown. This article explains how to create a wrapper function to make it work: http://thecodebarbarian.com/using-async-await-with-mocha-express-and-mongoose.html
I haven't tried it but was investigating this recently.
Use express-promise-router.
const express = require('express');
const Router = require('express-promise-router');
const router = new Router();
const mysql = require('mysql2');
const pool = mysql.createPool({
host: 'localhost',
user: 'myusername',
password: 'mypassword',
database: 'mydb',
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
}).promise();
router.get('/some_path', async function(req, res, next) {
const [rows, ] = await pool.execute(
'SELECT * ' +
'FROM mytable ',
[]
);
res.json(rows);
});
module.exports = router;
(The above is an example of using mysql2's promise interface with express-promise-router.)
Express 5 will automatically handle async errors for you
https://expressjs.com/en/guide/error-handling.html currently says it clearly:
Starting with Express 5, route handlers and middleware that return a Promise will call next(value) automatically when they reject or throw an error. For example:
app.get('/user/:id', async function (req, res, next) {
var user = await getUserById(req.params.id)
res.send(user)
})
If getUserById throws an error or rejects, next will be called with either the thrown error or the rejected value. If no rejected value is provided, next will be called with a default Error object provided by the Express router.
We can test that as follows:
const assert = require('assert')
const http = require('http')
const express = require('express')
const app = express()
app.get('/error', async (req, res) => {
throw 'my error'
})
const server = app.listen(3000, () => {
// Test it.
function test(path, method, status, body) {
const options = {
hostname: 'localhost',
port: server.address().port,
path: path,
method: method,
}
http.request(options, res => {
console.error(res.statusCode);
assert(res.statusCode === status);
}).end()
}
test('/error', 'GET', 500)
})
The terminal output on express#5.0.0-alpha.8 is the expected:
500
Error: my error
at /home/ciro/test/express5/main.js:10:9
at Layer.handle [as handle_request] (/home/ciro/test/node_modules/router/lib/layer.js:102:15)
at next (/home/ciro/test/node_modules/router/lib/route.js:144:13)
at Route.dispatch (/home/ciro/test/node_modules/router/lib/route.js:109:3)
at handle (/home/ciro/test/node_modules/router/index.js:515:11)
at Layer.handle [as handle_request] (/home/ciro/test/node_modules/router/lib/layer.js:102:15)
at /home/ciro/test/node_modules/router/index.js:291:22
at Function.process_params (/home/ciro/test/node_modules/router/index.js:349:12)
at next (/home/ciro/test/node_modules/router/index.js:285:10)
at Function.handle (/home/ciro/test/node_modules/router/index.js:184:3)
If you visit it on the browser, you will see an HTML page that says my error.
If you run the exact same code on express#4.17.1, you see on the terminal only:
UnhandledPromiseRejectionWarning: my error
but not the 500 nor my error. This is because the request just hangs forever. If you try to open it on the browser, you will see it hang more clearly.
TODO: how to make it show the stack trace as well instead of just my error? Getting the stack trace in a custom error handler in Express?
Express 4 solution
The simplest solution for Express 4 is to just wrap every single route in a try/catch as follows:
app.get('/error', async (req, res, next) => {
try {
throw new Error('my error'
res.send('never returned')
} catch(error) {
next(error);
}
})
which produces the same correct behavior as Express 5.
You can also factor this out further with some of the methods discussed at: express.js async router and error handling
Tested on Node.js v14.16.0.
To handle async requests in express routes use a try catch, which helps you to try for any errors in function and catch them. try{await stuff} catch{err}
An other less intrusive option is using express-async-errors
This will patch express to correctly handle async/await.
import express from 'express'
import 'express-async-errors'