SyntaxError: await is only valid in async function in nodeJs - node.js

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

Related

how to wrap axios function and let parent to wait?

here's I've my axios function wrapped within a custom function:
async function getOrder(orderId) {
// ...
await axios({
method: 'post',
url: endpoint + "/mymethod",
data: request
}).then(function (response) {
var data = response.data.result;
return data;
}).catch(function (error) {
return { "error": error };
});
}
but if than i call that function:
router.get('/getOrder/:id', (req, res) => {
let result = getOrder(req.params.id);
res.json(result);
})
it returns nothing (since its async and don't wait the .then()).
what's the best way to wrap axios/async function and call from outside?
I think you're missing await in your codes:
router.get('/getOrder/:id', async (req, res) => {
let result = await getOrder(req.params.id);
res.json(result);
})
====================
[New Update]
for me in API function:
async getOrder(orderId) {
try {
const response = await axios.post(endpoint + "/mymethod")
return response.data
} catch (error) {
return { "error": error }
}
}
and get the result:
router.get('/getOrder/:id', async (req, res) => {
let result = await getOrder(req.params.id);
res.json(result);
})
===========
[New Update2] here is my sample async/await function with axios
const axios = require("axios")
async function getOrder(orderId) {
try {
const response = await axios.get("http://google.com")
return response.data
} catch (error) {
return { "error": error }
}
}
async function main() {
let result = await getOrder();
console.log(result, "##")
}
main()
====================
[New Update3] new Promise with axios:
const axios = require("axios")
async function getOrder(orderId) {
// try {
// const response = await axios.get("http://google.com")
// return response.data
// } catch (error) {
// return { "error": error }
// }
return await new Promise((resolve, reject) => {
axios({
method: 'get',
url: "http://google.com"
}).then(function (response) {
var data = response.data
resolve(data)
}).catch(function (error) {
reject({ "error": error })
});
})
}
async function main() {
let result = await getOrder();
console.log(result, "##")
}
main()
I think you are missing an await so you do not return a promise but wait for the result of getOrder to be passed in res.json :
router.get('/getOrder/:id', async (req, res) => {
let result = await getOrder(req.params.id);
res.json(result);
})

Store data in an array using for each in node js sequelize

I am trying to push the fetched data in an array using foreach but it only returns the first data in the loop. Here is my code.
exports.getAllTrial = async function (req, res, next) {
try {
new Promise( async (resolve, reject) => {
var reservations = [];
await Schedule.getSchedule()
.then(data => {
data.forEach(async (element) => {
await saveReserve.getAllTrial({where: {scheduleID: element.id, date: "8/18/2020"}})
.then(trial => {
trial.forEach(response => {
reservations.push(response.scheduleID)
})
})
console.log(reservations);
resolve(reservations);
})
});
})
.then(value=>{
res.status(200).json(value);
})
.catch(err => {
console.log(err);
});
} catch (e) {
return res.status(400).json({ status: 400, message: e.message });
}
}
My expected output should be: [ 9, 10, 10 ] But it only returns [9].
Async code in a foreach loop is a bad idea, as it won't be executed one after the other. I suggest reading a bit more async/await and the concept of promise, as you are mixing things here (such as mixing await and .then). Also worth looking into Promise.all which will resolve a list of promises and array.map.
While I have no idea of what some variables such as saveReserve are supposed to be or do, your code might be simplified into:
exports.getAllTrial = async (req, res, next) => {
try {
const data = await Schedule.getSchedule()
const reservations = await Promise.all(
data.map(element => {
return saveReserve.getAllTrial({ where: { scheduleID: element.id, date: '8/18/2020' } })
})
)
return res.status(200).json(reservations)
} catch (e) {
return res.status(400).json({ status: 400, message: e.message })
}
}

How to handle async when making mongoose query in each array element in express?

On the following post method, I'm having some issues due to moongose async. res.send(suggestions) is executed first then Expense.findOne.exec
app.post('/suggestions', async function(req, res) {
const suggestions = await req.body.map((description) => {
Expense.findOne({ description: new RegExp(description, 'i') }).exec((err, result) => {
if (result) {
console.log(result.newDescription);
return {
description,
newDescription: result.newDescription,
category: result.category,
subcategory: result.subcategory
};
}
});
});
res.send(suggestions);
});
The result is a array of null values. How can I executed a query for each item, then execute res.send(suggestion)?
Found solution with the following code:
app.post('/suggestions', async function(req, res) {
try {
if (req.body.length > 0) {
const suggestions = req.body.map((description) =>
Expense.findOne({ description: new RegExp(description, 'i') })
);
const results = await Promise.all(suggestions);
return res.send(results);
}
} catch (e) {
console.log('error', e);
}
});

How to use result of called 'then' for next 'then'?

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

Res.Redirect is not getting called in Jest Test

i am using node-express and am trying to check the redirect when the call from API is successful. I am getting an error that - Expected mock function to have been called, but it was not called.
here is my function:
export function globalAuthHandler (req, res, next) {
const global_signin_url = config.get('url');
if (global_signin_url) {
console.log(global_signin_url);
fetch(global_signin_url)
.then((response) => response.json())
.then((response) => {
console.log('Response', response);
if (response.data) {
console.log('Success!!!');
res.redirect('/signIn');
} else {
console.log('going here 1' + response);
res.redirect('/session-expired');
throw Error(response.statusText);
}
})
.catch((error) => {
console.log('going global here 2 ' + error);
next(error);
});
} else {
console.log('going here 3');
res.redirect('/session-expired');
}
}
here is the test :
it('should throw the error and redirect if the API fails with 404.', async () => {
// Setup
Config.get = jest.fn();
Config.get.mockReturnValue(true);
Config.initialize = jest.fn(() => Promise.resolve({ data: {} }));
const req = jest.fn(),
res = { redirect: jest.fn() },
next = jest.fn();
//global.fetch = jest.fn(() => new Promise((resolve) => resolve({ response: { ok: false, status: 404 } })));
global.fetch = jest.fn(
() =>
new Promise((resolve) =>
resolve({
json: () => {
return { };
}
/* data: { ok: true } */
})
)
);
// Act
await middlewares.globalAuthHandler(req, res, next);
// Assert
expect(res.redirect).toHaveBeenCalled();
expect(res.redirect).toHaveBeenCalledWith('/signIn');
});
I am not able to figure out that - even after going to the success!!! log, redirect is not getting triggered.
Calling await on middlewares.globalAuthHandler doesn't wait for it to complete since it isn't returning the Promise.
Return the Promise created by fetch:
export function globalAuthHandler (req, res, next) {
...
return fetch(global_signin_url) // <= return the Promise
...
}
...and the test will wait for the Promise to resolve before continuing to the expect statements.
That will give res.redirect a chance to be called before it is tested.

Resources