Anyone has any idea about this and how would I be able to get the correct outcome?
I have used the Promise and async/await properties in here
layers = async () => {
return new Promise((resolve, reject) => {
let options = {
url: `http://geoserverIP/geoserver/rest/workspaces/datastores/featuretypes.json`,
auth: {
'user': 'admin',
'pass': 'geoserver'
}
}
request(options, (err, resp, body) => {
if (!err && resp.statusCode == 200) {
return resolve(JSON.parse(body))
} else if (!err) {
return reject({
status: 404,
errors: [{
messages: ["Workspace or datastore not found"]
}]
})
} else {
return reject({
status: 500,
errors: [{
messages: ["Failed connection with geoserver"]
}]
})
}
})
})
}
console.log(layers())
I expect to get the list of layers but I get "Promise {pending}"
When you mark a function as async by default returns a Promise also you are returning Promise explicitly.
To use the value either you can await the function or can make a .then chain.
(async ()=>{
const data = await layers();
console.log(data);
})();
or
layers().then((data)=>{
console.log(data)
});
Note: As you are not using any await keyword inside the function you don't need to mark it as async
EDIT1: You can use axios instead of request, it by default returns promise.
Related
I am working on a serverless function to be hosted on Netlify to subscribe users to a mailchimp email list.
I am getting the following obscure error:
lambda response was undefined. check your function code again
Here is my function:
const handler = async function (event, context) {
try {
let body = JSON.parse(event.body);
mailchimp.setConfig({
apiKey: 'XXXXXXXXX',
server: 'us20',
});
const submit = async () => {
const response = await mailchimp.lists.addListMember("XXXXXXXX", {
email_address: body.email.toLowerCase(),
status: 'subscribed'
});
if (response.errors !== undefined && response.errors.length) {
throw new Error(response.errors);
}
}
submit().then(response => {
console.log(response);
return {
statusCode: 200,
body: JSON.stringify({ response }),
}
}).catch(errors => {
return {
statusCode: 500,
body: JSON.stringify({ errors }),
}
});
} catch (error) {
// output to netlify function log
console.log(error);
return {
statusCode: 500,
// Could be a custom message or object i.e. JSON.stringify(err)
body: JSON.stringify({ msg: error.message }),
}
}
}
module.exports = { handler }
I think the issue may be because nothing is being returned after calling submit(), but I am not sure how best to return it. I still can't quite get my head around promises.
I am really hoping someone can point me in the right direction.
Many thanks
David
You are on the right track, nothing is returned in the submit function so the response will always be undefined.
Also You are using .then with async/await syntax which is ok, async/await is just a cleaner way of using promises so you typically use one or the other. And nesting catch blocks here is unnecessary. I would rewrite it to something like this:
const handler = async function (event, context) {
try {
let body = JSON.parse(event.body);
mailchimp.setConfig({
apiKey: 'XXXXXXXXX',
server: 'us20',
});
const submit = async () => {
const response = await mailchimp.lists.addListMember("XXXXXXXX", {
email_address: body.email.toLowerCase(),
status: 'subscribed'
});
if (response.errors !== undefined && response.errors.length) {
throw new Error(response.errors);
}
return response;
}
const response = await submit();
return {
statusCode: 200,
body: JSON.stringify({ response }),
}
} catch (error) {
// output to netlify function log
console.log(error);
return {
statusCode: 500,
// Could be a custom message or object i.e. JSON.stringify(err)
body: JSON.stringify({ msg: error.message }),
}
}
}
If you are still struggling with promises, Id recommend reading the docs for them as well as the docs for async/await.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
Having issues with using async and await. I'm executing two queries and then saving the result to a temp variable. After I have collected the response from all executed queries, I'm going to send that to the client.
Here is my current example code.
module.exports = (app) => {
app.get('/api/stats', (req, res) => {
let fetch1 = '';
let fetch2 = '';
conn.query('query here', [], async (error, results) => {
if (error) {
return res.send({
success: false,
message: 'There was an error.'
});
} else {
fetch1 = results;
}
});
conn.query('query here', [], async (error, results) => {
if (error) {
return res.send({
success: false,
message: 'There was an error.'
});
} else {
fetch2 = results;
}
});
// I need to wait until the queries have resolved so that I can send the correct data
return res.send({
success: true,
fetch1: fetch1,
fetch2: fetch2
});
});
};
I basically need to wait until the queries have been resolved so that I can send the correct data towards the end.
Can anyone explain how I can use await and async to accomplish this?
Thanks.
You can only await a Promise, so for functions that don't return Promises you need to create a Promise wrapper. This needs to be done per call that would previously use a callback, but you can make a helper function per function you need to wrap.
function queryPromise(query, parameters) {
return new Promise((resolve, reject) => {
conn.query(query, parameters, (err, results) => {
if(err) {
reject(err);
} else {
resolve(results);
}
});
});
}
module.exports = (app) => {
app.get('/api/stats', async (req, res) => {
try {
let fetch1 = await queryPromise('query here', []);
let fetch2 = await queryPromise('query here', []);
res.send({
success: true,
fetch1: fetch1,
fetch2: fetch2
});
} catch {
res.send({
success: false,
message: 'There was an error.'
});
}
});
};
From my knowledge, I usually apply async to functions and perform await on certain variables (inside the function) that need to be acquired from a specific database.
So to implement this into your function containing the async tag, you could possibly do:
fetch1 = await results;
fetch2 = await results;
This will wait until the data is attached onto the variable fetch1 and fetch2 before continuing on with the code.
Sorry if this was very vague, hopefully this was somewhat helpful.
I need some help on with a post method.
Here is a post method I use for some card payment using stripe
app.post('/charge', (req, res) => {
const amount = 2500;
stripe.customers
.create({
email: req.body.stripeEmail,
source: req.body.stripeToken,
})
.then((customer) =>
stripe.charges.create({
amount,
description: 'Web Development eBook',
currency: 'usd',
customer: customer.id,
})
)
.then((charge) => res.render('success'));
});
in the same method I want to add the following method which works for now only with postman
exports.addTransaction = async (req, res, next) => {
try {
const { text, amount } = req.body;
const transaction = await Transactions.create(req.body);
return res.status(201).json({
success: true,
data: transaction,
});
} catch (err) {
return res.status(500).json({
success: false,
error: 'Server Error! Transaction was not added',
});
}
};
and the body that I want to send through the POST method is smth like this
{
"text": "Book",
"amount": -23
}
I think you are confused by the async/await example. The async/await syntax works on the promise, just like the then function, the await waits for the function execution and returns the data to the variable which awaits the same.
Consider the following examples to check the difference between async/await and the promise syntax
function myPromise() {
return new Promise((resolve, reject) => {
resolve(5);
});
}
Now, we can call the above function with two different syntax
myPromise.then((data) => {
console.log(data); // prints 5
});
Or, we can use modern async/await like this,
const data = await myPromise();
The above function will only work if the function in which it is wrapped has async in the beginning.
for example:
async function getData() {
const data = await myPromise();
console.log(data);
}
Notice the async keyword before the function keyword, without the async keyword the function would not work.
Also, just like catch in the regular promise, we use try/catch to catch the errors.
Now, coming back to your problem, you could convert the second function to use then().catch() order or you could convert your first function to use async/await style. Or you can use the combination of both.
Below, I've implemented the then/catch version of your second function inside your first function
app.post('/charge', (req, res) => {
const { text, amount } = req.body;
stripe.customers
.create({
email: req.body.stripeEmail,
source: req.body.stripeToken,
})
.then((customer) =>
stripe.charges.create({
amount,
description: 'Web Development eBook',
currency: 'usd',
customer: customer.id,
});
)
.then((charge) => {
Transactions.create(req.body).then(() => {
res.status(201).json({
success: true,
data: transaction,
});
}).catch((e) => {
res.status(500).json({
success: false,
error: 'Server Error! Transaction was not added',
});
});
});
});
Right now I'm learning promises and want to get a token from a webserver, which also uses a promise. I tried it before without a promise but it's also not working.
This is the first block.
promise = new Promise(resolve => {
let accessToken = helper.getAccessToken(baseUrl);
let userCollection = helper.createCollection("user", db);
let excersizeCollection = helper.createCollection("excercise", db);
resolve({
accessToken: accessToken,
database: {
userCollection: userCollection,
excersizeCollection: excersizeCollection
}
});
});
promise
.then(promises => {
console.log("my token" + promises.accessToken);
new nceDefaultbotCommands(bot, promises.accessToken, baseUrl);
new botComamnds(bot, promises.database);
let userController = new reqUserController(
baseUrl,
0,
promises.accessToken
);
bot.start();
})
.catch(() => {
console.log("error");
});
Only the access token is not working, this is in my helper class and it looks like this.
static getAccessToken(baseUrl) {
let promise = new Promise(resolve => {
request.post(
{
url: baseUrl + "/token",
body: {
credentials: {
user: "USER",
password: "PW"
}
},
json: true //// Automatically parses the JSON string in the response
},
(error, response, body) => {
if (error) console.log("error");
if (!error && response.statusCode === 200) {
resolve({ token: body.token });
}
}
);
});
promise.then(resolve => {
console.log(resolve.token);
return resolve.token;
});
}
I get the access token but normally after the then of the first promise.
Thanks in advance.
You're fulfilling your first promise with an object, so that object is the fulfillment value (the promise isn't magically resolved to the promises that are values of properties on that object).
There's no reason to use new Promise when you have a promise or promises to work with, just chain off them; in this case, via Promise.all:
Promise.all([
helper.getAccessToken(baseUrl),
helper.createCollection("user", db),
helper.createCollection("excercise", db)
])
.then(([accessToken, userCollection, exersizeCollection]) => { // Note the destructuring
console.log("my token" + accessToken);
new nceDefaultbotCommands(bot, accessToken, baseUrl);
new botComamnds(bot, {userCollection, exersizeCollection});
let userController = new reqUserController(baseUrl, 0, accessToken);
bot.start();
})
.catch(/*...*/);
Note I corrected the spelling of "exercise," which may require changes to your botCommands constructor.
You do not return your Promise:
static getAccessToken(baseUrl) {
let promise = new Promise(resolve => {
...
});
return promise.then(resolve => {
console.log(resolve.token);
return resolve.token;
});
}
Then I think you need to handle it like Promise, somewhat like:
promise = new Promise(resolve => {
let accessToken = helper.getAccessToken(baseUrl).then(token => {
let userCollection = helper.createCollection("user", db);
let excersizeCollection = helper.createCollection("excercise", db);
resolve({
accessToken: accessToken,
database: {
userCollection: userCollection,
excersizeCollection: excersizeCollection
}
});
});
});
How would I structure a function that has multiple Mongoose.findOne() nested in each other?
I need to do something like
const userId = '...';
const postId = '...';
const imageId = '...';
User.findById(userId).then(user => {
if (!user) {
return res.status(400).json({
status: 'error',
err: 'User not found',
});
}
Post.findById(postId).then(post => {
if (!post) {
return res.status(400).json({
status: 'error',
err: 'Post not found',
});
}
Image.findById(imageId).then(image => {
if (!image) {
return res.status(400).json({
status: 'error',
err: 'Image not found',
});
// DO SOMETHING WITH VARIABLES 'user', 'post', AND 'image'
}).catch(err => { .. });
}).catch(err => { .. });
}).catch(err => { .. });
Since Collection.findById() returns a promise, I guess I should use chaining instead of this structure.
So it might be something like
User
.findById(userId)
.then(user => Post.findById(postId))
.then(post => Image.findById(imageId))
.then(image => {
// DO SOMETHING WITH VARIABLES 'user', 'post', AND 'image'
});
.catch(err => { .. });
but I don't know how to access the variables user, post, and image, and how to throw the errors, so I can access them in my catch statement.
Edit
I have tried this
async function getPostAsync() {
const userId = '597989c668189f31483ffdbf';
const postId = '597989c62624ea74750c74f8';
if (!userId) {
throw new Error('User id missing');
}
if (!postId) {
throw new Error('Post id missing');
}
const user = await User.findById(userId);
const post = await Post.findById(postId);
return post;
}
app.get('/', (req, res) => {
getPostAsync().then(post => {
res.json({
status: 'success',
});
}).catch(err => {
res.status(400).json({
status: 'error',
err
});
})
});
but I just receive
{
"status": "error",
"err": {}
}
Am I doing something wrong?
But I get the same result even with
async function getPostAsync() {
throw new Error('msg');
return Post.find();
}
so I might be calling the async function wrong.
You can use Promise.all:
Promise.all([
User.findById(userId),
Post.findById(postId),
Image.findById(imageId)
])
.then(result)=>{
let user = result[0];
let post = result[1];
let image = result[2];
})
.catch(err => { .. });
Or with destructing assignment:
Promise.all([
User.findById(userId),
Post.findById(postId),
Image.findById(imageId)
])
.then(([user, post, image])=>{...})
.catch(err => { .. });
You can't access those variables inside a later promise's then, but you can get round it by assigning the local resolved values to global variables
let globalUser, globalPost; // create variables for later
User
.findById(userId)
.then(user => {
globalUser = user; // assign to global
return Post.findById(postId)
})
.then(post => {
globalPost = post; // assign to global
return Image.findById(imageId)
})
.then(image => {
// DO SOMETHING WITH VARIABLES 'globalUser', 'globalPost', AND 'image'
})
.catch(err => {... });
EDIT: or when using async/await:
async function() {
const user = await User.findById(userId);
const post = await Post.findById(postId);
const image = await Image.findById(imageId);
// do something with user, post and image
}
Seeing as your promises don't rely on each other you could also use Promise.all() in an async function:
async function() {
const result = await Promise.all([
User.findById(userId),
Post.findById(postId),
Image.findById(imageId)
]);
const [user, post, image] = result;
// do something with user, post and image
}
EDIT 2: Error handling
async function getImage() {
let user;
try {
user = await User.findById(userId);
} catch (error) { // deal with rejection of `User.findById`
// do something with error
}
// if these fail the entire function will throw
const post = await Post.findById(postId);
const image = await Image.findById(imageId);
return image;
}
getImage()
.then(image => {... })
.catch(error => {... }); // deal with rejection of `getImage` as a whole
The above code showcases the ways you can handle errors in an async function. The first is how we deal with an error in the User.findById function, by simply wrapping it in a try catch block.
The second method is by simply letting the entire async function throw an error. I.e. if the Post.findById or Image.findById promises reject, the entire getImage() promise will reject, which you can deal with in the .catch() handler.