Search code examples
node.jspromiserequestclover-payment

NodeJS joining promise with request functions


I have the following code below for clover payment api and although the code works perfectly, I do not get a response back when I call the api from postman. I know this is because of the multiple requests in the service and I tried to find a cleaner way to do it but keep failing to get it to work. I am trying to send back the final response which is the response of the request in the postPayment() function. Any help would be appreciated.

my service code is:

const db = require('../_helpers/db');
const crypto = require('crypto');
const request = require("request-promise");


module.exports = {
    getAll
};

var targetEnv = 'https://sandbox.dev.clover.com/v2/merchant/';
var cardNumber = '6011361000006668';

async function getAll(data) {
  var url = targetEnv + data.merchant_id + '/pay/key';

  var options = {
    url: url,
    method: 'GET',
    headers: {
      Authorization: 'Bearer ' + data.api_token
    }
  };

  request(options, (error, response, body) => {
    if (!error && response.statusCode === 200) {
      console.log('getAll ' +data);
      processEncryption(JSON.parse(body), JSON.stringify(data));
    }
  });
}

// Process the encryption information received by the pay endpoint.
function processEncryption(jsonResponse, data) {
  console.log('processEncryption ' +data);
  var prefix = jsonResponse['prefix'];
  var pem = jsonResponse['pem'];

  // create a cipher from the RSA key and use it to encrypt the card number, prepended with the prefix from GET /v2/merchant/{mId}/pay/key
  var encrypted = crypto.publicEncrypt(pem, Buffer(prefix + cardNumber));

  // Base64 encode the resulting encrypted data into a string to Clover as the 'cardEncrypted' property.
  var cardEncrypted = new Buffer(encrypted).toString('base64');

  return postPayment(cardEncrypted, data);
}

// Post the payment to the pay endpoint with the encrypted card information.
async function postPayment(cardEncrypted, body) {
  // POST to /v2/merchant/{mId}/pay
  console.log('mid ' +JSON.parse(body));
  var posturl = targetEnv + '9ZQTAJSQKZ391/pay';
  var postData = {
    "orderId": "4N3RBF33EBEGT",
    "currency": "usd",
    "amount": 2,
    "tipAmount": 0,
    "taxAmount": 0,
    "expMonth": 12,
    "cvv": 123,
    "expYear": 2018,
    "cardEncrypted": cardEncrypted,
    "last4": 6668,
    "first6": 601136,
    "streetAddress": "123 Fake street",
    "zip": "94080",
    "merchant_id": "9ZQTAJSQKZ391",
    "order_id": "4N3RBF33EBEGT",
    "api_token": "4792a281-38a9-868d-b33d-e36ecbad66f5"
  }

  var options = {
    url: posturl,
    method: 'POST',
    headers: {
      'Authorization': 'Bearer ' + "4792a281-38a9-868d-b33d-e36ecbad66f5",
    },
    json: postData
  };

   request(options, (error, response, body) => {
    if (!error && response.statusCode === 200) {
      //console.log(response);  
      return response;   <---- this response is what i need to show in postman
    }
  });
   console.log(response);
}

my controller is:

const express = require('express');
const router = express.Router();
const tableOrderService = require('./cloverPayment.service');

// routes
router.post('/getAll', getAll);


module.exports = router;


function getAll(req, res, next) {
    tableOrderService.getAll(req.body)
        .then(users => res.json(users))
        .catch(err => next(err));
}

Solution

  • Your asynchronous functions getAll() and postPayment() are not properly returning an asynchronous value (either via callback or promise).

    I'd suggest converting everything to promises and returning a promise from getAll() and from postPayment(). And, since converting to promises, I'd remove the deprecated request-promise library in favor of the got() library. Then, you can call getAll(), get a promise back and use either the resolved value or the rejection to send your response from the actual request handler:

    const db = require('../_helpers/db');
    const crypto = require('crypto');
    const got = require('got');
    
    module.exports = {
        getAll
    };
    
    var targetEnv = 'https://sandbox.dev.clover.com/v2/merchant/';
    var cardNumber = '6011361000006668';
    
    async function getAll(data) {
        console.log('getAll ', data);
        const url = targetEnv + data.merchant_id + '/pay/key';
    
        const options = {
            url: url,
            method: 'GET',
            headers: {
                Authorization: 'Bearer ' + data.api_token
            }
        };
        const response = await got(options);
        return processEncryption(response, data);
    }
    
    // Process the encryption information received by the pay endpoint.
    function processEncryption(jsonResponse, data) {
        console.log('processEncryption ' + data);
        const prefix = jsonResponse.prefix;
        const pem = jsonResponse.pem;
    
        // create a cipher from the RSA key and use it to encrypt the card number, prepended with the prefix from GET /v2/merchant/{mId}/pay/key
        const encrypted = crypto.publicEncrypt(pem, Buffer(prefix + cardNumber));
    
        // Base64 encode the resulting encrypted data into a string to Clover as the 'cardEncrypted' property.
        const cardEncrypted = Buffer.from(encrypted).toString('base64');
        return postPayment(cardEncrypted, data);
    }
    
    // Post the payment to the pay endpoint with the encrypted card information.
    function postPayment(cardEncrypted, body) {
        // POST to /v2/merchant/{mId}/pay
        console.log('mid ', body);
        const posturl = targetEnv + '9ZQTAJSQKZ391/pay';
        const postData = {
            "orderId": "4N3RBF33EBEGT",
            "currency": "usd",
            "amount": 2,
            "tipAmount": 0,
            "taxAmount": 0,
            "expMonth": 12,
            "cvv": 123,
            "expYear": 2018,
            "cardEncrypted": cardEncrypted,
            "last4": 6668,
            "first6": 601136,
            "streetAddress": "123 Fake street",
            "zip": "94080",
            "merchant_id": "9ZQTAJSQKZ391",
            "order_id": "4N3RBF33EBEGT",
            "api_token": "4792a281-38a9-868d-b33d-e36ecbad66f5"
        }
    
        const options = {
            url: posturl,
            method: 'POST',
            headers: {
                'Authorization': 'Bearer ' + "4792a281-38a9-868d-b33d-e36ecbad66f5",
            },
            json: postData
        };
    
        return got(options);
    }
    

    And, then your controller:

    const express = require('express');
    const router = express.Router();
    const tableOrderService = require('./cloverPayment.service');
    
    // routes
    router.post('/getAll', (req, res) => {
        tableOrderService.getAll(req.body)
            .then(users => res.json(users))
            .catch(err => next(err));
    });
    
    module.exports = router;