I'm setting up a GraphQL resolver to call a Braintree endpoint. The Braintree npm package wants to call their endpoint with code that looks like this:
braintreeGateway.customer.create({
firstName: "Jen",
lastName: "Smith",
company: "Braintree",
email: "jen@example.com",
phone: "312.555.1234",
fax: "614.555.5678",
website: "www.example.com"
}, function (err, result) {
result.success;
result.customer.id;
});
GraphQL resolvers return promises. I'm trying to figure out how to promisify this callback, and include it within a promise resolver.
I've read a lot of SO posts about promisifying a callback, but the ones I've found so far don't seem to quite match up to this use case.
I've tried a lot of things, this being the latest:
getBrainTreeCustomerId: (parent, args, context) => {
const userid = context.userId;
const braintreeCustomerCreate = util.promisify(braintreeGateway.customer.create);
async function run_braintreeCustomerCreate() {
try {
let braintreeCustomerId = await braintreeCustomerCreate({
firstName: "Jen",
lastName: "Smith",
company: "Braintree",
email: "jen@example.com",
phone: "312.555.1234",
fax: "614.555.5678",
website: "www.example.com"
});
return braintreeCustomerId
}
catch (err) {
console.log('ERROR:', err);
}
}
return Promise.resolve()
.then(() => {
let braintreeCustomerId = (async () => {
let braintreeCustomerId = await run_braintreeCustomerCreate()
return braintreeCustomerId;
})();
return braintreeCustomerId;
})
.then((braintreeCustomerId) => {
return braintreeCustomerId;
})
.catch((err) => {
console.log(err);
});
}
}
But the catch handler gets an error saying "Cannot read property '_createSignature' of undefined".
What's the correct syntax to use here?
By setting the promisified function outside of the scope of the gateway you might be separating it too much from the BrainTree
object structure. The error sounds like it's trying to access another internal function that's no longer in scope. Try this instead without using util.promisify
:
async function run_braintreeCustomerCreate() {
return new Promise((resolve, reject) => {
braintreeGateway.customer.create(
{
firstName: "Jen",
lastName: "Smith",
company: "Braintree",
email: "jen@example.com",
phone: "312.555.1234",
fax: "614.555.5678",
website: "www.example.com"
},
(err, result) => {
if (err) return reject(err);
return resolve(result);
}
);
});
}
This will return a Promise that either resolves or rejects based on the result of the call while calling in a way consistent with the object.
Another way that may work would be to add the promisified function to the customer object like this:
const createAsPromise = util.promisify(braintreeGateway.customer.create);
braintreeGateway.customer.createAsPromise = createAsPromise;
async function run_braintreeCustomerCreate() {
try {
let braintreeCustomerId = await braintreeGateway.customer.createAsPromise(
{ /* data */ }
);
return braintreeCustomerId;
}
catch(err) console.log('ERROR:', err);
}
As a general note, you don't need to do catching earlier in the chain as the .catch
will work and it simplifies your logic by removing the need for the try
at all. Also note that the object returned from the create
call will contain an Id but is not itself just the Id - it's an object. In fact having the try
with catch
there will block the error from being seen by whoever calls it because it will end up returning nothing (ie, undefined
) as the resolved value.