I have a Flutter app and I'm trying to get a client nonce from braintree. Per the braintree documentation, I have this in my cloud function:
exports.getClientNonce = functions.https.onCall(async (data, context) => {
gateway.clientToken.generate({}, function (err, response) {
if (err) {
throw new functions.https.HttpsError('unknown', 'Error getting client nonce');
} else {
console.log(`token: ${response.clientToken}`);
return response.clientToken;
}
});
});
Then, in my Flutter app I call the function (again, I'm following what the plugin says):
try {
HttpsCallable callable = CloudFunctions.instance.getHttpsCallable(
functionName: 'getClientNonce',
);
dynamic result = await callable.call({});
final value = result.data;
debugPrint('token: $value');
var data = await BraintreePayment().showDropIn(
nonce: value,
amount: '2.0',
enableGooglePay: false,
inSandbox: true);
print("Response of the payment $data");
} on CloudFunctionsException catch (e) {
debugPrint('An error occurred');
} catch (e) {
debugPrint('An error occurred');
}
}
I tried changing the cloud function so that it only returns a random number (as soon as the function is executed), and my Flutter app is correctly receiving the value (so the cloud function is communicating fine). And in my Firebase console, I am able to view the client nonce specified by console.log
. But the function is for whatever reason unable to return the actual client nonce. (It should be should be some string hash that is >2000 characters long)
The callable function needs to return a promise from the top-level of the function callback that resolves with the value to return. Right now, you're returning nothing from the top-level. The return you have now is just returning a value from the inner callback function that you pass to braintree API. This isn't going to propagate to the top level.
What you need to do is either use a version of braintree API that returns an API (if one exists), or promisify the existing call that uses a callback.
See also "3. Node style callback" here: How do I convert an existing callback API to promises?
I have not tested this, but the general format if you apply that pattern will look more like this:
exports.getClientNonce = functions.https.onCall(async (data, context) => {
return new Promise((resolve, reject) => {
gateway.clientToken.generate({}, function (err, response) {
if (err) {
reject(new functions.https.HttpsError('unknown', 'Error getting client nonce'));
} else {
console.log(`token: ${response.clientToken}`);
resolve(response.clientToken);
}
});
});
});