I want to return what I get after an async call.
So
app.get("/books", async (req, res) => {
let books = await getBooks()
.then(json => {
res.status(200).send({"books": json});
});
});
Should wait on rendering the result until the called getBooks is done.
export async function getBooks() {
console.log("Getting books from cloud");
Book.findAll({
// ...
}).then(books => {
console.log("Got books");
return JSON.stringify(books, null, 4);
});
}
But right now the response gets rendered without actually waiting for the result.
You don't need to use promises. You can just use await and then use the result of that.
app.get("/books", async (req, res) => {
const books = await getBooks();
res.status(200).send({ books });
});
I'd highly suggest taking it a step further and using try/catch to handle failure cases
app.get("/books", async (req, res) => {
try {
const books = await getBooks();
res.status(200).send({ books });
} catch (error) {
// massage this to send the correct status code and body
res.status(400).send( { error });
}
});
You can use await in second method too:
export async function getBooks() {
console.log("Getting books from cloud");
var books = await Book.findAll({
// ...
})
if(books){
console.log("Got books");
return JSON.stringify(books, null, 4);
}
You just need to return your promise, and since you're just returning a promise you don't need async;.
app.get("/books", async (req, res) => {
let json = await getBooks()
res.status(200).send({"books": json});
});
export function getBooks() {
console.log("Getting books from cloud");
return Book.findAll({
// ...
}).then(books => {
console.log("Got books");
return JSON.stringify(books, null, 4);
});
}
app.get("/books", async (req, res) => {
let books = await getBooks();
res.status(200).send({"books": books});
})
Related
I have created the following function that makes a call to a third party API to create an order and on the response iam calling model function that checks if a user with the user ID exits or not and some operation is done accordingly.
createOrder: async function (req, res, next) {
let formData = req.body;
razorPayInstance.instance.orders.create({
amount: formData.amount * 100,
currency: "INR",
payment_capture: 1
})
.then(response => {
let planSubscription = await PlanSubscription.findOne({ user_id:formData.user_id });
if(planSubscription) {
// do something
} else {
// do something
}
return res.status(200).json(res.fnSuccess(response));
})
.catch(error => {
console.log(error);
});
}
Iam getting the following error in node console :
let planSubscription = await PlanSubscription.findOne({ user_id:formData.user_id });
^^^^^
SyntaxError: await is only valid in async function
Can anybody please point out what is wrong here
You can't await some expression inside a function which is not async. Just use async function inside then.See more about await here
createOrder: async function (req, res, next) {
let formData = req.body;
razorPayInstance.instance.orders.create({
amount: formData.amount * 100,
currency: "INR",
payment_capture: 1
})
.then(async(response) => { //change here
let planSubscription = await PlanSubscription.findOne({ user_id:formData.user_id });
if(planSubscription) {
// do something
} else {
// do something
}
return res.status(200).json(res.fnSuccess(response));
})
.catch(error => {
console.log(error);
});
}
The async function below is supposed to check if a url is a legit url
let CheckUrl = function (url, done) {
dns.lookup(url, function(err, address) {
if (err) return done(err);
done(null, true); //return true because I don't care what the address is, only that it works
});
}
The express.js code below gets the url but I'm having trouble understanding how to write the if statement so that it returns true or false.
// Gets URL
app.post("/api/shorturl/new", function(req, res) {
if (CheckUrl(req.body.url)) {
// do something
}
});
I'm not sure what to pass as the second argument in CheckUrl() in this if statement. Or maybe I wrote the first async function incorrectly to begin with?
Please use the async await
I have written a test code for you as below:
const express = require('express');
const app = express();
const dns = require('dns');
let CheckUrl = function (url, done) {
return new Promise((resolve, reject) => {
dns.lookup(url, function(err, address) {
console.log("err " , err)
if (err) {
resolve(false)
} else {
resolve(true)
}
});
});
}
app.post("/api/shorturl/new", async function(req, res) {
try {
let result = await CheckUrl(req.body.url);
console.log("result " , result)
res.send(result)
}
catch (error) {
console.log("in catch error " , error)
res.send(error)
}
});
app.listen(3000)
you can get the knowledge to know about the Promise here. The Promise object represents the eventual completion (or failure) of an asynchronous operation and its resulting value.
As mentioned by DeepKakkar, this was what I was looking for:
app.post("/api/shorturl/new", async (req, res) => {
try {
let result = await CheckUrl(req.body.url);
res.send(result)
}
catch (error) {
return new Error('Could not receive post');
}
});
My code block for crud.js is as follows,
const listall = () => {
return client.connect(() => {
return client.invoke("ZSD_CP_PRICE_GET_ALL", {}, (err, res) => {
if (err) {
console.log('error in invoke', err);
}
console.log("ZSD_CP_PRICE_GET_ALL", res);
return res;
});
});
}
My code block for viewpage.js is as follows,
router.get('/', function(req, res) {
res.render('viewpage', {title: 'SAP', data: sapview.listall()})
})
module.exports = router;
My code block for viewpage.jade is as follows,
extends layout
block content
h1= title
p Welcome to #{title}
p Data #{data}
When I run the node application terminal logs the result like,
ZSD_CP_PRICE_GET_ALL {
IS_RETURN: {
TYPE: ''
}
But the res is never returned as I mentioned in "return res" after the console.log block in crud.js file
client.connect() is asynchronous; you have no way of getting the actual return value of whatever further asynchronous code (such as client.invoke) you call.
I suggest promisifying the invocation,
const listall = () => {
return new Promise((resolve, reject) => {
client.connect(() => {
client.invoke("ZSD_CP_PRICE_GET_ALL", {}, (err, res) => {
if (err) {
return reject(err);
}
resolve(res);
});
});
});
};
and then getting the data in an async function:
router.get("/", async (req, res) => {
const data = await sapview.listall();
res.render("viewpage", { title: "SAP", data });
});
(A further refactoring would involve a generic promisified "invoke method" function.)
I have the following Express endpoint:
const all = require('promise-all');
router.post('/verify', upload.single('photo'), async (req, res) => {
...
await all({'p1': p1, 'p2': p2}).then((response) => {
...
console.log("Response:",
ruleCtrl.manageRule(detection, res);
});
});
ruleCtrl.manageRuleis as follows:
export async function manageRule(identifierDetected, res) {
let rule = db.getRule(identifierDetected);
await all([rule]).then((ruleExtracted) => {
...
res.json(ruleExtracted);
}).catch((err) => {
res.status(418).send("DOCUMENT_NOT_RECOGNIZED");
});
}
and db.getRule:
export async function getRule(idRule) {
return new Promise((resolve, reject) => {
Rule.findOne({ruleID: idRule}, (err, rule) => {
if (err) {
reject("MongoDB Rule error: " + err);
} else {
resolve(rule);
}
});
})
}
My response is into manageRule and this function depends of the values extracted into the await all. So, right now, Express is returning a response before get the information from mongoose database (db).
Which is the way to handle this issue?
Thanks everyone!
I would refactor your code a bit to make it easier to read, and also return the result from ruleCtrl.manageRule(detection, res);.
The request might simply be timing out since your original code is missing a return there or an await (to make sure it finishes executing)
Express endpoint:
const all = require('promise-all');
router.post('/verify', upload.single('photo'), async (req, res) => {
...
// Catch any exceptions from the promises. This is the same as using .catch
try {
// Lets assign the returned responses to variable
let [p1Result, p2Result] = await all({'p1': p1, 'p2': p2});
...
console.log("Responses:", p1Result, p2Result);
// return the response from manageRule method
return ruleCtrl.manageRule(detection, res);
} catch(err) {
// Handle err here
}
});
One of the great benefits with async await is moving away from chained promises, so simply return the result from the await to a variable instead of using .then()
ruleCtrl.manageRule
export async function manageRule(identifierDetected, res) {
// Use try catch here to catch error from db.getRule. Assign to variable and return
// res.json
try {
let ruleExtracted = await db.getRule(identifierDetected);
...
return res.json(ruleExtracted);
} catch(err) {
return res.status(418).send("DOCUMENT_NOT_RECOGNIZED");
}
}
You dont have to return res.json or res.status here, I just like to keep track of when I want to end function execution.
You could refactor the ruleCtrl.manageRule method even further by not sending in res as a parameter but by returning the result from db.getRule instead. Let router.post('/verify) handle req and res, so to make it even easier to read.
I originally had try...catch in my getAllUsers method for querying but ended up removing it because as far as I could tell it wasn't doing anything. I know the async function returns a promise so it should be fine and actually based on how the code is structured I think it's required otherwise the try...catch in the query would swallow the error. Is there anything I'm missing with this structure and use of async/await, try...catch, and .then .catch?
let getAllUsers = async () => {
let res = await models.users.findAll({
attributes: [ 'firstName', 'lastName' ]
});
return res;
};
router.get(`${path}`, (req, res) => {
queries.users.getAllUsers()
.then(users => {
res.status(200).json(users);
})
.catch(error => {
res.status(500).send(error)
});
});
There's just no reason to use await at all in your function. Instead of this:
let getAllUsers = async () => {
let res = await models.users.findAll({
attributes: [ 'firstName', 'lastName' ]
});
return res;
};
It can just be this:
let getAllUsers = () => {
return models.users.findAll({
attributes: [ 'firstName', 'lastName' ]
});
};
You just return the promise directly and the caller uses the promise the same as you already were. Since you are not using the result within your getAllUsers() function or coordinating it with anything else, there's no reason to use await. And, since there's no use of await, there's no reason for the function to be declared async either.
If you wanted to use await, you could use it for the caller of getAllUsers() like this:
router.get(`${path}`, async (req, res) => {
try {
let users = await queries.users.getAllUsers();
res.status(200).json(users);
} catch(error => {
res.status(500).json(error);
}
});
And, here you would have to use try/catch in order to catch rejected promises. Personally, I don't see how this is particularly better than what you had originally with .then() and .catch() so for a situation as simple as this (with no coordination or serialization with other promises), it's really just a matter of personal preference whether to use .then() and .catch() or await with try/catch.
You would use async/await with the code that calls getAllUsers rather than using it in getAllUsers itself:
const getAllUsers = () => {
return models.users.findAll({
attributes: [ 'firstName', 'lastName' ]
});
};
router.get(`${path}`, async (req, res) => {
try {
const users = await queries.users.getAllUsers();
res.status(200).json(users);
} catch (error) {
res.status(500).send(error)
}
});
The best way I have found to handle this is using middleware.
Here is the function:
// based upon this
// http://madole.xyz/error-handling-in-express-with-async-await-routes/
// https://github.com/madole/async-error-catcher
export default function asyncErrorCatcher(fn) {
if (!(fn instanceof Function)) {
throw new Error("Must supply a function");
}
return (request, response, next) => {
const promise = fn(request, response, next);
if (!promise.catch) {
return;
}
promise.catch((error) => {
console.log(error.message);
response.sendStatus(500);
});
};
}
Here is the usage:
router.get("/getSettings/", asyncErrorCatcher(async (request: Request, response: Response) => {
const settings = await database.getSettings();
response.json(settings);
}));