如何使用 AWS Lambda Node.js 服务器实施 Braintree 并生成带有承诺的客户端令牌?

How to implement Braintree with AWS Lambda Node.js server and generate a client token with a promise?

我正在尝试生成 Braintree 的 clientToken,我应该从 Braintree 网关获取它,根据此处找到的文档,当我的 UI 触发时,我需要我的 lambda 连接到该网关: https://developers.braintreepayments.com/start/hello-server/node

我正在尝试在 Lambda 函数中实现此功能,我需要将其导出以供我的无服务器应用程序的其余部分使用。此外,我正在尝试根据需要使用 ES6 import 语句来导入 Braintree 功能。虽然,即使我使用 require 语句,我也会得到同样的错误。

这是我的 Lambda 函数:

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
    });
  }
}

只有第一个 console 语句实际打印任何东西,之后从 gateway.clientToken.generate({}) 开始一切都失败,最重要的是它失败时没有抛出任何错误....

当我输出console.log("getting client token: ", gateway);

我得到这样的数据结构:

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:


...........



所以我试着把这个:gateway.clientToken.generate({})改成这个:

TypeError: Cannot read property 'clientToken' of undefined"

我假设那里什么都没有。

如何使用 ES6 导入语句在我的无服务器 lambda 函数中生成 Braintree 令牌?

我意识到,由于这些 lambda 是异步函数,而且由于我们必须等待 Braintree 返回的响应,因此我们必须声明嵌套 async/await 语句的正确组合。

下面的代码是我使用正确的承诺链实现来正确处理 async 过程的最终实现:

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
    });
  }
}