GQL resolver: returning null - javascript

I'm calling data from an API and have a resolver that looks like this:
Query: {
async getSomething(parent, args, ctx, info) {
const kek = yada.aol.emails(function (err, res) {
return[{name: "lmao"}]
// returns null every time
})
return [{name: "lol"}]
// returns correctly
},
},
However, the data I need to return would be the response within the function. I was wondering as to why anything I return that's nested in that function returns null and how I can continue to shape the data appropriately?

The namecheap.domains.getList function is asynchronous. Your last return is executed before the callback function (err, res) {}. You need to return a Promise.
Either namecheap.domains.getList supports Promises and you can return it directly (but I don't know what that is), or you can make the callback function resolve a Promise:
Query: {
getDomains(parent, args, ctx, info) {
return new Promise((resolve, reject) => {
namecheap.domains.getList((err, res) => {
if (err) return reject(err);
resolve(res);
})
});
},
},

Related

How to wrap function call inside of Promise

After exporting the required modules and setting up the variables
let AWS = require("aws-sdk");
const AmazonCognitoIdentity = require('amazon-cognito-identity-js');
const USER_POOL_ID = 'us-east-1_vkXRQuP4U';
const CLIENT_ID = 'mipa4trls0l7323om33mlk80e8';
const poolData = {
UserPoolId : USER_POOL_ID, ClientId : CLIENT_ID
};
const POOL = new AmazonCognitoIdentity.CognitoUserPool(poolData);
let email = "my.email#domain.com";
let password = "My.Password!";
I can go ahead and call signUp command:
POOL.signUp(email, password, [], null, function(err, result) {
console.log('...result:', result);
});
And it works well. Next I want to wrap the POOL.signUp(email, password...) inside async function sign_up like so:
async function sign_up(email, password) {
POOL.signUp(email, password, [], null, function(err, result) {
console.log('...sign_up.result:', result);
return result;
})
};
async function main() {
let signupData = await sign_up(email, password);
console.log('...main.signupData:', signupData);
return signupData;
};
main().then((error, data) => {console.log('...error, data:', error, data)});
While it works fine, the order of the calls that get executed is wrong as the main function doesn't wait for the sign_up() function to complete. In attempt to correct this behavior I wrap the POOL.signUp(email, password...) inside of Promise:
async function sign_up(email, password) {
return await new Promise((resolve) => {
POOL.signUp(email, password, [], null, {
onSuccess: (result) => {
console.log('...result:', result)
return resolve(result);
},
onFailure: (err) => {
return resolve(err.message);
},
});
})
};
But I am getting the error message:
UnhandledPromiseRejectionWarning: TypeError: callback is not a function
Is there a way to avoid this error?
don't need to await the Promise you are returning (since we precisely want our function to be async, we want to defer the waiting to the caller)
Promise constructor function needs to provide the second reject parameter to be able to access the callback in the function implementation
pass a callback function as your POOL.signUp fourth argument, instead of an object
function sign_up(email, password) {
return new Promise((resolve, reject) => {
POOL.signUp(email, password, [], null, function(err, result) {
if (err) {
return reject(err.message);
}
console.log('...result:', result)
resolve(result);
});
})
};

Promisify Express response.render method

I need to create a render method to build html blocks into a string.
It seems to work but I used the notorious "new Promise" and I wanted to know if what I've done is either correct or not:
async render(req, res) {
const locals = await this.execute(req); // DB operation, retrieve context
return new Promise((resolve, reject) => {
try {
return res.render('my-view', { ...locals, layout: null }, (err, html) => {
if (err) {
return reject(err);
}
return resolve(html);
});
} catch (err) {
return reject(err);
}
});
}
Thank you!
The new Promise constructor implicitly catches (synchronous) exceptions from the executor callback, so that try/catch is not needed. Also, the return value is ignored. You'd write just
async render(req, res) {
const locals = await this.execute(req); // DB operation, retrieve context
return new Promise((resolve, reject) => {
res.render('my-view', { ...locals, layout: null }, (err, html) => {
if (err) reject(err);
else resolve(html);
});
});
}

Make the return statement wait until everything else in the function is finished

I'm trying to make a function that returns the results of a SOAP call (using npm-soap in combination with node.js). The problem is that the function returns undefined because the SOAP call isn't finished yet when the return statement is reached.
I tried putting the return statement in the SOAP call callback itself, but then it returns undefined. I think this is because the return statement should be in the outer function instead of the inner function, just like I did in the example below. A console.log() in the SOAP call callback outputs the right data, so I know it's there.
How do I make the return statement wait on the inner SOAP call? Thanks!
var config = require('./config.js');
var soap = require('soap');
function getInvoices() {
let invoices;
// Connect to M1
soap.createClient(config.endpoint, function(err, client) {
// Log in
client.login(
{
username: config.username,
apiKey: config.password
},
function(err, loginResult) {
// Get invoices
client.salesOrderInvoiceList(
{
sessionId: loginResult.loginReturn.$value
},
function(err, invoiceResult) {
// Save invoices
invoices = invoiceResult;
console.log(invoices); // <- Returns the right data
// Log out
client.endSession(
{
sessionId: loginResult.loginReturn.$value
},
function(err, logoutResult) {
}
);
}
);
});
});
// Return invoices
return invoices; // <- Returns undefined
}
console.log(getInvoices(); // <- So this returns undefined as well
Have getInvoices return a Promise which you can then resolve once all the callbacks finish i.e.
function getInvoices() {
return new Promise((resolve, reject) => {
// Connect to M1
soap.createClient(config.endpoint, (err, client) => {
if (err) return reject(err);
// Log in
client.login({
username: config.username,
apiKey: config.password
}, (err, loginResult) => {
if (err) return reject(err);
// Get invoices
client.salesOrderInvoiceList({
sessionId: loginResult.loginReturn.$value
}, (err, invoiceResult) => {
if (err) return reject(err);
// Log out & resolve the Promise
client.endSession({
sessionId: loginResult.loginReturn.$value
}, (err, logoutResult) =>
err ? reject(err) : resolve(invoiceResult)
);
});
});
});
}
...
(async () => {
try {
const invoices = await getInvoices();
console.log(invoices);
} catch (e) {
console.error(e);
}
})();

Properly chaining functions in Firebase function

I am building a function in Firebase Cloud Functions, which can utilize Node.js modules.
I am still new to the use of .then() and I'm struggling to figure out a way to chain my 3 functions webhookSend(), emailSendgrid(), and removeSubmissionProcessor() that happen right after the 'count' is incremented (the if statement that checks temp_shouldSendWebhook). The whole idea of returning promises still confuses me a little, especially when it it involves external libraries.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const request = require('request');
const firebaseConfig = JSON.parse(process.env.FIREBASE_CONFIG);
const SENDGRID_API_KEY = firebaseConfig.sendgrid.key;
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(SENDGRID_API_KEY);
exports.submissionProcess = functions.database.ref('/submissions/processor/{submissionId}').onWrite((change, context) => {
var temp_metaSubmissionCount = 0; // omitted part of function correctly sets the count
var temp_shouldSendWebhook = true; // omitted part of function correctly sets the boolean
return admin.database().ref('/submissions/saved/'+'testuser'+'/'+'meta').child('count')
.set(temp_metaSubmissionCount + 1)
.then(() => {
// here is where im stuck
if (temp_shouldSendWebhook) {
webhookSend();
emailSendgrid();
removeSubmissionProcessor();
} else {
emailSendgrid();
removeSubmissionProcessor();
}
})
.catch(() => {
console.error("Error updating count")
});
});
function emailSendgrid() {
const user = 'test#example.com'
const name = 'Test name'
const msg = {
to: user,
from: 'hello#angularfirebase.com',
subject: 'New Follower',
// text: `Hey ${toName}. You have a new follower!!! `,
// html: `<strong>Hey ${toName}. You have a new follower!!!</strong>`,
// custom templates
templateId: 'your-template-id-1234',
substitutionWrappers: ['{{', '}}'],
substitutions: {
name: name
// and other custom properties here
}
};
return sgMail.send(msg)
}
function webhookSend() {
request.post(
{
url: 'URLHERE',
form: {test: "value"}
},
function (err, httpResponse, body) {
console.log('REQUEST RESPONSE', err, body);
}
);
}
function removeSubmissionProcessor() {
admin.database().ref('/submissions/processor').child('submissionkey').remove();
}
I want to be able to construct the 3 functions to be called one after another such that they will all execute.
In order to chain these functions, they each need to return a promise. When they do, you can call them sequentially like this:
return webhookSend()
.then(() => {
return emailSendgrid();
})
.then(() => {
return removeSubmissionProcessor();
});
Or in parallel like this:
return Promise.all([webhookSend, emailSendgrid, removeSubmissionProcessor]);
Now, to make your functions return promises:
emailSendgrid: It looks like this returns a promise (assuming sgMail.send(msg) returns a promise), so you shouldn't need to change this.
removeSubmissionProcessor: This calls a function that returns a promise, but doesn't return that promise. In other words it fires off an async call (admin.database....remove()) but doesn't wait for the response. If you add return before that call, this should work.
webhookSend calls a function that takes a callback, so you'll either need to use fetch (which is promise-based) instead of request, or you'll need to convert it to return a promise in order to chain it:
function webhookSend() {
return new Promise((resolve, reject) => {
request.post(
{
url: 'URLHERE',
form: {test: "value"}
},
function (err, httpResponse, body) {
console.log('REQUEST RESPONSE', err, body);
if (err) {
reject(err);
} else {
resolve(body);
}
}
);
});
}
Use async functions and then you can use .then() or await before every function calls
for reference read this

Abstract function in order to let choose to return promises or callback

I don't know maybe it's an antipattern.
Soon very young developers will join our developer team, and I would like to let them choose if they want to use the module with callback or Promises pattern.
This function basically save data into the database. I repeat the db.insert flow in order to abstract the function, but is there an other way to do this?
function create(data, callback) {
if(callback) {
db.insert(data, function(err, doc) {
return callback(err, doc);
});
} else {
return new Promise(function(res, rej) {
db.insert(data, function(err, doc) {
if(err) {
return reject(err);
}
return resolve(doc);
});
});
}
}
I like the bluebird .asCallback(...) approach:
function somethingAsync(cb) {
return somePromise().asCallback(cb);
}
...essentially, you return a promise and call a callback (if one was passed). Therefore, it can be used either way. If you don't want to adopt Bluebird, you can essentially do the same thing like this:
function somethingAsync(cb) {
var promise = somePromise();
if (!cb) return promise;
promise.then(res => cb(null, res), err => cb(err));
}
You can just implement the callback and then use the pify module to add the promise.
You could just implement the normal CPS (continuation passing style) function and include a generic promisify function that adapts cps functions to promise-returning functions.
function create (data, k) {
db.insert(data, k)
}
function promisify (f) {
return function (...args) {
return new Promise (function (resolve, reject) {
f (...args, function (err, result) {
if (err)
reject(err)
else
resolve(result)
})
})
}
}
You can use it with the continuation like this
create (data, function(err, res) {
if (err)
// do something with the error
else
// do something with the result
})
Or you can use promises like this
promisify(create)(data)
.then(res => {
// do something with the result
})
.catch(err => {
// do something with the error
})
You'll notice that the create function is pretty redundant tho. There's really no need to wrap the db.insert like this. Instead, skip creating the create function and just use both like this
// for cps, use normal api
db.insert(data, function(err, res) { ... })
// for promises, use the wrapper
promisify(db.insert)(data).then( ... )

Categories