I am trying to generate Braintree's clientToken
that I am supposed to get from the Braintree gateway that I need my lambda to connect to when triggered by my UI according to the docs found here: https://developers.braintreepayments.com/start/hello-server/node
I am trying to implement this within a Lambda function that I need to export for use by the rest of my serverless application. Furthermore, I am trying to use ES6 import
statements as needed to import the Braintree functionality. Although, I get the same error even if I use require
statements.
Here is my Lambda function:
import * as dynamoDbLib from "./libs/dynamodb-lib";
import { success, failure } from "./libs/response-lib";
import braintree from "braintree";
export async function main(event, context) {
/*
All secrets are declared in the serverless template for the specific function
and stored in AWS SecretsManger
*/
// create a Braintree gateway
let gateway = braintree.connect({
environment: braintree.Environment.Sandbox, // either Sandbox or Production
merchantId: process.env.merchantId, // these come from the Lambda's environmental variables
publicKey: process.env.publicKey,
privateKey: process.env.privateKey
});
/*************************************************
* Braintree related functions based on documentation at
* https://developers.braintreepayments.com/start/hello-server/node
*/
/////////////////////////////////////
// get a client token from Braintree and send it to the client
/////////////////////////////////////
const getClientToken = (options = {}) => {
console.log("getting client token: ", gateway); // console.logs will show up in AWS Cloudwatch
let customerId = options && options.hasOwnProperty("customerID")
? options.customerID
: null;
// THIS IS THE ONLY THING THAT PRINTS TO CONSOLE!!!
console.log("This is customerID: ", customerId);
// NONE OF THIS WORKS!!!???
gateway.clientToken.generate({})
.then((res) => {
console.log("maybe result: ", res); // <---- None of these print!?!?
console.log("Maybe success/fail: ", res.success);
console.log("maybe token: ", res.clientToken);
// Code here
})
.catch (err => {
console.log("ERROR CAUGHT: ", err);
failure({
status: false,
error: "did it trigger 2: " + err
});
}
);
};
// try to execute API calls
try {
switch (event.pathParameters.txnMethod) {
case "get-client-token":
// call getClientToken with the parsed version of optional body if present, otherwise call it with nothing
getClientToken(
event.hasOwnProperty("body")
? JSON.parse(event.body)
: null
);
break;
default:
failure({
status: false,
error: "invalid query string"
});
break;
}
} catch (error) {
failure({
status: false,
error: "Did it trigger 1: " + error
});
}
}
Only the first console
statements actually print anything, after that everything fails from gateway.clientToken.generate({})
on down and most importantly it fails without any error thrown....
When I output console.log("getting client token: ", gateway);
I get a data structure like this:
getting client token: BraintreeGateway {
config:
Config {
timeout: 60000,
apiVersion: '5',
graphQLApiVersion: '2018-09-10',
publicKey: 'sbxkeys',
privateKey: 'sbxkeys',
merchantId: 'sbxkeys',
environment:
Environment {
server: 'api.sandbox.braintreegateway.com',
port: '443',
authUrl: 'https://auth.sandbox.venmo.com',
ssl: true,
graphQLServer: 'payments.sandbox.braintree-api.com',
graphQLPort: '443' } },
graphQLClient: GraphQLClient { _service: GraphQL { config: [Config] } },
http:
Http {
config:
Config {
timeout: 60000,
apiVersion: '5',
graphQLApiVersion: '2018-09-10',
publicKey: 'sbxkeys',
privateKey: 'sbxkeys',
merchantId: 'sbxkeys',
environment: [Environment] } },
addOn:
AddOnGateway {
gateway: [Circular],
config:
Config {
timeout: 60000,
apiVersion: '5',
graphQLApiVersion: '2018-09-10',
publicKey: 'sbxkeys',
privateKey: 'sbxkeys',
merchantId: 'sbxkeys',
environment: [Environment] } },
address:
AddressGateway {
gateway: [Circular],
config:
Config {
timeout: 60000,
apiVersion: '5',
graphQLApiVersion: '2018-09-10',
publicKey: 'sbxkeys',
privateKey: 'sbxkeys',
merchantId: 'sbxkeys',
environment: [Environment] } },
clientToken:
ClientTokenGateway {
gateway: [Circular],
config:
Config {
timeout: 60000,
apiVersion: '5',
graphQLApiVersion: '2018-09-10',
publicKey: 'sbxkeys',
privateKey: 'sbxkeys',
merchantId: 'sbxkeys',
environment: [Environment] } },
creditCard:
CreditCardGateway {
gateway: [Circular],
config:
Config {
timeout: 60000,
apiVersion: '5',
graphQLApiVersion: '2018-09-10',
publicKey: 'sbxkeys',
privateKey: 'sbxkeys',
merchantId: 'sbxkeys',
environment: [Environment] } },
creditCardVerification:
...........
So i try to change this: gateway.clientToken.generate({})
to this:
gateway.BraintreeGateway.clientToken.generate({})
in the hopes that the `generate() method is associate to that structure and the following is the error that I receive when I test it:TypeError: Cannot read property 'clientToken' of undefined"
Im assuming there is nothing there.
How do I get the Braintree token to generate in my serverless lambda function using ES6 import statements??
I realized that being that these lambda's are async functions and that since we have to wait for the response back from Braintree, we therefore have to declare the right combination of nested async/await
statements.
The code below is the final implementation I committed with the correct promise chain implementation to handle the async
process correctly:
import * as dynamoDbLib from "./libs/dynamodb-lib";
import { success, failure } from "./libs/response-lib";
import braintree from "braintree";
export async function main(event, context) {
/*
All secrets are declared in the serverless template for the specific function
and stored in AWS SecretsManger
*/
// create a Braintree gateway
let gateway = braintree.connect({
environment: braintree.Environment.Sandbox, // either Sandbox or Production
merchantId: process.env.merchantId, // these come from the Lambda's environmental variables
publicKey: process.env.publicKey,
privateKey: process.env.privateKey
});
/*************************************************
* Braintree related functions based on documentation at
* https://developers.braintreepayments.com/start/hello-server/node
*/
/////////////////////////////////////
// get a client token from Braintree and send it to the client
/////////////////////////////////////
const getClientToken = async (options = {}) => {
console.log("Getting client token...");
//console.log("hasOwnProps: ", options.hasOwnProperty("customerID") );
let customerId = options && options.hasOwnProperty("customerID")
? options.customerID
: null;
console.log("This is customerID: ", customerId);
return await gateway.clientToken.generate({});
};
/////////////////////////////////////
// purchase an item using Braintree's transaction method
/////////////////////////////////////
const purchaseItem = async (purchaseInformation) => {
/* console.log(
"purchaseInformation: ",
util.inspect(purchaseInformation, { showHidden: false, depth: null })
); */
return await gateway.transaction.sale(
{
amount: purchaseInformation.amount,
paymentMethodNonce: purchaseInformation.nonce,
options: {
submitForSettlement: true
}
}
);
};
/*************************************************
* Enter here
*/
// view the event that was received
console.log("event: ", event);
let result;
// try to execute API calls
try {
switch (event.pathParameters.txnMethod) {
case "get-client-token":
// call getClientToken with the parsed version of optional body if present, otherwise call it with nothing
await getClientToken(
event.hasOwnProperty("body")
? JSON.parse(event.body)
: null)
.then((res) => {
//console.log("maybe result: ", res);
//console.log("Maybe success/fail: ", typeof(res.success));
//console.log("maybe token: ", res.clientToken);
// Code here
if(res.success.toString() === "true"){
//console.log("SUCCESS token: ", res.clientToken);
return context.succeed(success({
status: true,
clientToken: res.clientToken
}));
} else {
return failure({
status: false,
error: "Braintree ClientToken Failure."
});
}
})
.catch (err => {
console.log("ERROR CAUGHT: ", err);
return failure({
status: false,
error: "did it trigger 2: " + err
});
});
break;
case "purchase-item":
console.log("purchasing item");
const data = JSON.parse(event.body);
await purchaseItem(data)
.then((res) => {
// Code here
if(res.success === true){
console.log("~~~~~~~~~~~");
console.log("This is RES: ", res);
console.log("This is ERR>RES: ", res.ErrorResponse);
return context.succeed(success({
status: true,
TxnAuth: res
}));
} else if (res.success === false) {
console.log("#################");
console.log(res.result);
return failure({
status: false,
error: "Error validating payment server information"
});
} else {
return failure({
status: false,
error: "Braintree Server Failure."
});
}
})
.catch (err => {
console.log("ERROR CAUGHT: ", err);
console.log("*********");
return failure({
status: false,
error: "did it trigger 3pmt: " + err
});
});
break;
default:
return failure({
status: false,
error: "invalid query string"
});
break;
}
} catch (error) {
return failure({
status: false,
error: "API Call to Braintree Failed: " + error
});
}
}