0

I'm trying to make a post request in Twilio functions to process a charge with the USAePay gateway API but my code seems to be tripping somewhere. Any insight is appreciated. I think it may be the callback() function being in the wrong place.

I also get a a warning that buffer is depreciated, how can I work around that?

Here is my code:

exports.handler = function(context, event, callback) {
//setup dependencies
const express = require('express');
const bodyParser = require('body-parser');
const request = require('request');
const sha256 = require('sha256');

const app = express();
app.use(express.static('public'));
app.use(bodyParser.json());

//setup authorization for API request
var seed = "abcdefghijklmnop";
var apikey = "xxxxxxxxxxxxxxxxxxxxxxxx";
var prehash = apikey + seed;
var apihash = 's2/'+ seed + '/' + sha256(prehash);
var authKey = new Buffer(apikey + ":" + apihash).toString('base64');
var authorization = "Basic " + authKey;

//POST endpoint for API request
app.post('/', (req, res) => {
    //setup request for API using provided info from user
    let options = {
        url: 'https://sandbox.usaepay.com/api/v2/transactions',
        method: 'POST',
        json: true,
        headers: {
            "Authorization": authorization
        },
        body: {
    "command": "cc:sale",
    "amount": "5.00",
    "amount_detail": {
        "tax": "1.00",
        "tip": "0.50"
    },
    "creditcard": {
        "cardholder": "John doe",
        "number": "4000100011112224",
        "expiration": "0919",
        "cvc": "123",
        "avs_street": "1234 Main",
        "avs_zip": "12345"
    }
        }
    };
    //make request and handle response
    request(options, (err, apiRes, body) => {
        if(err) {
            res.status(500).json({message: "internal server error"});
        }
        else{
            res.status(200).json({
                result: body.result,
                error: body.error || ""
            });
        
        }
    });
        });
        
};
jack
  • 330
  • 3
  • 12
  • Hello! You say you are doing this in Twilio Functions, but this appears to be an Express app and doesn't show usage of a `callback` at all. Is this the correct code sample? – philnash Nov 04 '21 at 03:53
  • @philnash Thanks for the quick response. Yes its in Twilio functions I tried to copy this code from github hoping it would work in Twilio and adding these dependencies. I removed the callback since it would fire immediately without executing. If you can point out what's the best way to post to a external API that would be great! – jack Nov 04 '21 at 04:00

1 Answers1

0

Twilio developer evangelist here.

I recommend you read up about how Twilio Functions works. You do not just import a Node application without changes. You need to export a function called handler.

The handler function is called when a request is made to the URL of the Twilio function.

The function receives three arguments, a context, an event and the callback function. The context contains environment variables amongst other things, the event contains all the parameters from an HTTP request (either query string parameters or parameters in the request body) and the callback is for returning a response.

A basic Twilio Function looks like this:

exports.handler = function (context, event, callback) {
    return callback(null, { hello: "World!" });
}

In this case, making a request to the Function's URL will receive a JSON response of { "hello": "World!" }.

Now, in your case you need to make a request to an external API as part of the request to the Function. First, I recommend you set secrets like your API Key in environment variables. They can then be accessed from the context object. Your API call will be asynchronous, so the important thing is to only call the callback function when all your asynchronous calls are finished.

Something like this might work:

const request = require("request");
const sha256 = require("sha256");

exports.handler = function (context, event, callback) {
  const seed = context.SEED;
  const apikey = context.API_KEY;
  const prehash = apikey + seed;
  const apihash = "s2/" + seed + "/" + sha256(prehash);
  const authKey = Buffer.from(apikey + ":" + apihash).toString("base64");
  const authorization = "Basic " + authKey;

  const options = {
    url: "https://sandbox.usaepay.com/api/v2/transactions",
    method: "POST",
    json: true,
    headers: {
      Authorization: authorization,
    },
    body: {
      command: "cc:sale",
      amount: "5.00",
      amount_detail: {
        tax: "1.00",
        tip: "0.50",
      },
      creditcard: {
        cardholder: "John doe",
        number: "4000100011112224",
        expiration: "0919",
        cvc: "123",
        avs_street: "1234 Main",
        avs_zip: "12345",
      },
    },
  };
  //make request and handle response
  request(options, (err, apiRes, body) => {
    if (err) {
      const response = new Twilio.Response();
      response.setStatusCode(500);
      response.appendHeader("Content-Type", "application/json");
      response.setBody({ message: "internal server error" });
      callback(null, response);
    } else {
      callback(null, {
        result: body.result,
        error: body.error || "",
      });
    }
  });
};

The request package has been deprecated for some time now, so you might want to consider updating it to something that is still maintained.

But the most important thing to do is learn how Twilio Functions work by reading the documentation.

philnash
  • 70,667
  • 10
  • 60
  • 88
  • Thanks! that worked. Though I did utilize functions in the past and I understand the importance of `callback()` functions The 3rd party API call kind of threw me off. What libraries would you suggest work best in making a post request in a Twilio function? – jack Nov 04 '21 at 05:10
  • 1
    I like using [got](https://www.npmjs.com/package/got) or [node-fetch](https://www.npmjs.com/package/node-fetch) and others like [axios](https://www.npmjs.com/package/axios) (which is also the HTTP client underneath the Twilio package). – philnash Nov 04 '21 at 05:12