Call DynamoDb scan recursively when Promisified - node.js

I need to get some data from DynamoDb, using the scan() method. I have implemented some basic pagination by calling my function recursively n number of times to get the correct page.
Currently, I call my function and inside the scan() callback, if the data can be send back, I use the handler callback to return the data.
CURRENT CODE
const AWS = require('aws-sdk')
const docClient = new AWS.DynamoDB.DocumentClient()
const TABLE_NAME = process.env.TABLE_NAME
const DEFAULT_PAGE_SIZE = 500
const DEFAULT_PAGE_NUMBER = 1
const self = {
handler: (event, context, callback) => {
const {pageNumber, pageSize} = event.queryStringParameters ? event.queryStringParameters : {pageNumber: DEFAULT_PAGE_NUMBER, pageSize: DEFAULT_PAGE_SIZE}
const params = {
TableName: ORGANISATION_TYPES_TABLE_NAME,
Limit: pageSize ? pageSize : DEFAULT_PAGE_SIZE
}
return self.scan(params, pageNumber, 1, callback)
},
scan: (params, pageNumber, pageCount, callback) => {
docClient.scan(params, (err, data) => {
if (err) {
callback(null, {
statusCode: 500,
body: JSON.stringify(err)
})
};
if (data.LastEvaluatedKey && pageCount < pageNumber) {
pageCount += 1
params.ExclusiveStartKey = data.LastEvaluatedKey
self.scan(params, pageNumber, pageCount, callback)
} else {
callback(null, {
statusCode: 200,
body: JSON.stringify(data)
})
}
})
}
}
module.exports = self
The above code does work, allowing me to specify a pageSize and pageNumber query parameter.
However, I want to Promisify self.scan.
I tried the following, but it results in the response being undefined
DESIRED CODE
const AWS = require('aws-sdk')
const docClient = new AWS.DynamoDB.DocumentClient()
const ORGANISATION_TYPES_TABLE_NAME = process.env.ORGANISATION_TYPES_TABLE_NAME
const DEFAULT_PAGE_SIZE = 500
const DEFAULT_PAGE_NUMBER = 1
const self = {
handler: (event, context, callback) => {
const {pageNumber, pageSize} = event.queryStringParameters ? event.queryStringParameters : {pageNumber: DEFAULT_PAGE_NUMBER, pageSize: DEFAULT_PAGE_SIZE}
const params = {
TableName: ORGANISATION_TYPES_TABLE_NAME,
Limit: pageSize ? pageSize : DEFAULT_PAGE_SIZE
}
return self.scan(params, pageNumber, 1).then((response) => {
callback(null, {
statusCode: 200,
body: JSON.stringify(response)
})
}).catch((err) => {
callback(null, {
statusCode: 500,
body: JSON.stringify(err)
})
})
},
scan: (params, pageNumber, pageCount) => {
return new Promise((resolve, reject) => {
docClient.scan(params, (err, data) => {
if (err) {
reject(err)
};
if (data.LastEvaluatedKey && pageCount < pageNumber) {
pageCount += 1
params.ExclusiveStartKey = data.LastEvaluatedKey
self.scan(params, pageNumber, pageCount, callback)
} else {
resolve(data)
}
})
})
}
}
module.exports = self
I also tried just doing return Promise.resolve(data) inside the docClient.scan() callback, but that doesn't work either. It's as if promises cannot be resolved inside a callback?

I have recently helped someone with this problem, there's actually quite an elegant solution that we hit upon that uses the hasNextPage property on the response you get from the SDK. The key is to have your recursive function pass an array that holds your results through the recursive calls and just concat until you run out of pages and then just return the array.
const scan = async params => {
function scanRec(promise, xs) {
return promise
.then(async result => {
const response = result.$response;
const items = xs.concat(result.Items);
response.hasNextPage() ? scanRec(response.nextPage().promise(), items) : items
})
}
return scanRec(docClient.query(params).promise(), []);
}
You'd then use the function in the normal way:
const params = { /** params **/ };
scan(params).then(x => {
// ...
})

Related

TypeError: Cannot read properties of undefined (reading 'MatchList')

I have this:
let list = GetList(JSON.stringify(data),"");
console.log( list.SearchResult.MatchList);
and I have this issue:
TypeError: Cannot read properties of undefined (reading 'MatchList')
I added console logo to list console.log(list);
I get this :
{
SearchResult: { MatchList: [ [Object] ], numOfMatches: 1, totalMatches: 1 }
}
this is in console, why I can't get MatchList
console
let list = GetList(JSON.stringify(data),"");
console.log( list );
I get
{
SearchResult: { MatchList: [ [Object] ], numOfMatches: 1, totalMatches: 1 }
}
getlist function:
exports.GetList = async (req, res) => {
const data = await petition({
url: URLGateway,
method: 'POST',
body: req,
});
return data;
};
get petition function:
const petition = async ({url, method, contentype, body}) => {
const URL = process.env.URL + url;
const USER = process.env.USER;
const PASS = process.env.PASSWORD;
try
{
const options = {
method: method,
rejectUnauthorized: false,
digestAuth: `${USER}:${PASS}`,
contentType: contentype,
data: body,
};
const responseHandler = (err, data, res) => {
if (err) {
console.log("ERROR: ", err);
}
}
const { data } = await httpClient.request(URL, options, responseHandler);
const result = JSON.parse( data.toString('utf8') );
return {
res: result,
};
}
catch (Exception)
{
console.log("Exception: ", Exception);
}
}
module.exports = petition;
the function Getlist call function petition, This function allows me to obtain the data that is in the endpoint ( url )
This is exactly what I was thinking... console.log(list) is not giving you that return, it certainly gives you Promise something. GetList returns a promise (because of the async keyword) and a promise does not have SearchResult. You need to await first.
// Either await the before storing into list:
let list = await GetList(JSON.stringify(data),"");
console.log( list.SearchResult.MatchList);
// Or await before using the value
console.log((await list).SearchResult.MatchList);

How to properly make a promise.all function with a .map?

I attempted to ask a simplified version of this here but I realized that it probably doesn't contain enough information. So unfortunately I'm just going to post the whole thing and hope that it doesn't offend anyone.
Basically I have 4 functions, with their stated purposes below:
1.InitializeDrive() takes a user email and uses Google's JWT user impersonation method to return the appropriate authorization for that user.
2.listfiles() calls on InitializeDrive() for authorization and retrieves a list of the documents associated with the associated user auth.
3.singleUserData() expects a list of the files such as that from listfiles() and refines them.
4.all_user_data() is intended to be the Promise.all async function that combines all of the aforementioned functions, and maps to an array of users getListUsers(), creating a master array containing all of the refined file data for each user.
Basically my poorly formed and ignorant question is 'how can make the all_user_data() in such a way that it will return the aforementioned master array?'. I am relatively new to async programming, and have a persistent problem getting confused with nested functions.
// loads credentials from .env file
require('dotenv').config();
const util = require('util');
const { google } = require('googleapis');
const { logger } = require('handlebars');
const { getListUsers } = require('./get_users');
const target_users = getListUsers();
function initializeDrive(version, user) {
return new Promise((resolve, reject) => {
const client_email = process.env.GOOGLE_CLIENT_EMAIL;
console.log(client_email);
// add some necessary escaping so to avoid errors when parsing the private key.
const private_key = process.env.GOOGLE_PRIVATE_KEY.replace(/\\n/g, '\n');
// impersonate an account with rights to create team drives
const emailToImpersonate = user;
const jwtClient = new google.auth.JWT(
client_email,
null,
private_key,
['https://www.googleapis.com/auth/drive'],
emailToImpersonate,
);
return google.drive({
version: version,
auth: jwtClient,
});
});
}
const listfiles = async (pagetokenObj, user) => {
let pageToken = '';
let version = 'v3';
if (pagetokenObj !== undefined) {
pageToken = pagetokenObj.pageToken;
}
const drive = await initializeDrive(version, user);
//const drive = initializeDrive(version,user);
return new Promise((resolve, reject) => {
drive.files.list(
{
pageSize: 100,
fields:
'nextPageToken, files(id, name, owners(emailAddress),
sharingUser(emailAddress), permissions)',
...(pageToken ? { pageToken } : {}),
},
function (err, { data: { nextPageToken = '', files = [] } = {} }) {
if (err) {
return reject(err);
}
if (!nextPageToken) {
return resolve(files);
}
// if page token is present we'll recursively call ourselves until
// we have a complete file list.
return listfiles({ pageToken: nextPageToken }).then((otherfiles) => {
resolve(files.concat(otherfiles));
});
},
);
});
};
//Function returns formatted
const singleUserData = async (files) => {
return new Promise((resolve, reject) => {
const single_user_json = await listfiles();
const res = single_user_json
.filter((doc) => Boolean(doc.permissions))
.map((doc) => {
return {
id: doc.id,
sharedWith: doc.permissions
.filter((permission) => permission.type === 'user')
.map((permission) => {
return {
emailAddress: permission.emailAddress,
role: permission.role || null,
};
}), // convert the perm object into a string (email address)
};
});
// this is how you get nicer console.logs instead of just [Object] and [Array] BS
// https://stackoverflow.com/a/10729284/9200245
console.log(util.inspect(res, { showHidden: false, depth: null, colors: true }));
if (err) {
return reject(err);
}
if (!nextPageToken) {
return resolve(files);
};
})
};
const all_user_data = async() => {
const users = await getListUsers();
const pagetokenObj = "{ pageToken = '' } = {}";
Promise.all(
users.map(async (pagetokenObj,user) => {
const files = await listfiles(pagetokenObj, user);
console.log(files);
const singleUserData = await singleUserData(files)
console.log(singleUserData);
}),
);
console.log(users)
}
//returnJSON();
//getListUsers();
//singleUserData();
all_user_data();
I finally figured it out. Basically needed to await a lot more and properly declare async.
// loads credentials from .env file
require('dotenv').config();
const util = require('util');
const { google } = require('googleapis');
const { logger } = require('handlebars');
const { getListUsers } = require('./get_users');
const target_users = getListUsers();
async function initializeDrive(user) {
// return new Promise((resolve, reject) => {
const client_email = process.env.GOOGLE_CLIENT_EMAIL;
console.log(user + ': ' + client_email);
// add some necessary escaping so to avoid errors when parsing the private key.
const private_key = process.env.GOOGLE_PRIVATE_KEY.replace(/\\n/g, '\n');
// impersonate an account with rights to create team drives
const emailToImpersonate = await user;
const jwtClient = new google.auth.JWT(
client_email,
null,
private_key,
['https://www.googleapis.com/auth/drive'],
emailToImpersonate,
);
return google.drive({
version: "v3",
auth: jwtClient,
});
//});
}
//
async function listfiles(pagetokenObj, user) {
let pageToken = '';
if (pagetokenObj !== undefined) {
pageToken = pagetokenObj.pageToken;
}
const drive = await initializeDrive(user);
//console.log(drive)
return new Promise((resolve, reject) => {
drive.files.list(
{
pageSize: 100,
fields:
'nextPageToken, files(parents, id, name, properties, owners(emailAddress), sharingUser(emailAddress), permissions)',
...(pageToken ? { pageToken } : {}),
},
function (err, { data: { nextPageToken = '', files = [] } = {} }) {
if (err) {
return reject(err);
}
if (!nextPageToken) {
return resolve(files);
}
// if page token is present we'll recursively call ourselves until
// we have a complete file list.
return listfiles({ pageToken: nextPageToken }).then((otherfiles) => {
resolve(files.concat(otherfiles));
});
},
);
});
};
async function singleUserData(user) {
const pagetokenObj = "{ pageToken = '' } = {}"
const single_user_json = await listfiles(pagetokenObj, user);
// return new Promise ((resolve, reject) => {
console.log(user+ ":" + JSON.stringify(single_user_json));
const res = await single_user_json
.filter((doc) => Boolean(doc.permissions))
.map((doc) => {
return {
id: doc.id,
sharedWith: doc.permissions
.filter((permission) => permission.type === 'user')
.map((permission) => {
return {
emailAddress: permission.emailAddress,
role: permission.role || null,
};
}) // convert the perm object into a string (email address)
};
});
return JSON.stringify(res);
//})
}
async function getAllUserData() {
try {
const users = await getListUsers();
// const userString = JSON.parse(users);
console.log("test22222222222222: " + users)
const usersData = await Promise.all(
users.map((user) => {
return singleUserData(user);
})
);
console.log("[" + usersData + "]");
return usersData;
} catch (error) {
console.log(error);
}
}
getAllUserData();
You're almost there.
Remove listfiles call in all_user_data
Pass user to singleUserData
Remove pagetokenObj in all_user_data
Remove async and await inside users.map and return promise directly
Await Promise.all, assign it to a variable and return that variable
Remove unnecessary Promise wrapping in singleUserData
Change function signature of singleUserData to take in a user
Pass user to listfiles in singleUserData
Return res instead of files in singleUserData
Here are the changes I made to all_user_data and singleUserData:
// Function returns formatted
async function singleUserData(user) {
const single_user_json = await listfiles(user);
const res = single_user_json
.filter((doc) => Boolean(doc.permissions))
.map((doc) => {
return {
id: doc.id,
sharedWith: doc.permissions
.filter((permission) => permission.type === "user")
.map((permission) => {
return {
emailAddress: permission.emailAddress,
role: permission.role || null,
};
}), // convert the perm object into a string (email address)
};
});
return res;
};
async function getAllUserData() {
const users = await getListUsers();
const usersData = await Promise.all(
users.map((user) => {
return singleUserData(user);
})
);
return usersData;
};
const usersData = await getAllUserData();

context.hasRole is not a function in Nodejs sinon testing issue

I had made function to fetch cloudwatch details from AWS.I trying to create a testcase in node.js and using sinon but i am getting a context.hasRole is not defined because i am checking this in my function file which is cloudwatch.js.
Can you please help me to fake this test
"-----cloudwatch.spec.js-------"
describe('cloudwatch', () => {
let sandbox = null;
beforeEach(() => {
sandbox = sinon.createSandbox(AWS.config);
})
afterEach(() => {
sandbox.restore()
})
it('Should return queryid', async () => {
let queryId = {
queryId: "12ab3456-12ab-123a-789e-1234567890ab"
};
const body = {
endTime: 34568765,
queryString: 'filter #message like /Audit/',
startTime: 34565678,
limit: 100,
logGroupName: '/aws/lambda/dev-api--service-sandbox-api'
};
let params = {}
let queryid = {
queryId: 6786971301298309123
};
await cloudwatch.startQuery(context, params, body, callback);
sinon.match(queryId)
})
})
"------Cloudwatch.js----"
let cloudwatch = module.exports = {};
const AWS = require('aws-sdk');
const nconf = require('nconf');
const {
HttpResult,
HttpUnauthorizedError,
AmazonCloudWatchLogsClient
} = require('api-lib');
AWS.config = nconf.get('amazonCloudWatchLogsClient');
cloudwatch.startQuery = async function(context, params, body,
callback) {
body.startTime = new Date(body.startTime).valueOf();
body.endTime = new Date(body.endTime).valueOf();
if (!context.hasRole("read:cloudwatch"))
return callback(new HttpUnauthorizedError("context missing role
read:cloudwatch"));
const amazonCloudWatchLogsClient = new
AmazonCloudWatchLogsClient(AWS.config);
let result = await amazonCloudWatchLogsClient.startQuery(body,
function(err) {
console.log("Error", err);
});
callback(null, new HttpResult(result));
};
cloudwatch.getQueryResults = async function(context, params,
requestBody, callback) {
console.log(requestBody)
let test = requestBody.queryId;
test = test.toString();
requestBody.queryId = test;
if (!context.hasRole("read:cloudwatch"))
return callback(new HttpUnauthorizedError("context missing role
read:cloudwatch"));
const amazonCloudWatchLogsClient = new
AmazonCloudWatchLogsClient(AWS.config);
let result2 = await
amazonCloudWatchLogsClient.getQueryResults(requestBody.queryId,
function(err) {
console.log("Error", err);
});
callback(null, new HttpResult(result2));
};
I am using eslint and except from chai for comparing the output to the sample output.

undefined result nodejs async await

i'm testing await functions but i have an "undefined" result when i check the return of the async function, my express function is like this (i removed unnecesary code, just to show how i am using the async
const getAppsConsumptionSum = async (msisdn, startPeriod, endPeriod) => {
var urlTigoPlus = 'http://...';
var args = {
requestConfig: {
timeout: config.get('localServer.remoteTimeout')
}
};
remoteApi = await restClient.get(url, args,
async (data, response) => {
if (response.statusCode === 200) {
sumatoria = await group(data.arrayofdata).by('subapplication').reduce(async function(id, entries) {
return {
appname: id,
mb: (entries.map(getBytes).reduce(add)) / 1048576
};
});
return sumatoria;
} else {
next(utils.error(503));
}
}
);
};
exports.dataAppsConsumption = async function(req, resp, next) {
let prepaidQuery = 'select ...';
const resultPrepaid = await clientDseDev.execute(prepaidQuery)
.then(async resultPrepaid => {
sumatoria = await getAppsConsumptionSum(variable1, startPeriod, endPeriod);
console.log('this variable shows undefined ' + sumatoria)
//i tried also with this
getAppsConsumptionSum(variable1, startPeriod, endPeriod).then((sumatoria) => {
console.log('this variable shows undefined ' + sumatoria)
});
})
.catch((err) => {
console.log(err)
});
};
thanks all for your help, #jfriend00 solution was right, also i had to add a return before the call to the axios function
return axios.get(url, options
)
.then(async function (response) {
if (response.status === 200){
group(response.data.arrayofdata).by('subapplication').reduce(function(id, entries) {
return {
appname: id,
mb: (entries.map(getBytes).reduce(add)) / 1048576
};
});
return sumatoria;

Nodejs promise all not running as expected

I have a series of promises which I have chained in testCard. This method takes a stripe card number, get the token from stripe and then talks to a third party API which tries to perform purchases with that card.
I need to run testCard by looping through an array of card numbers. To do this I have a controller object with a method testAllCards which takes the array of numbers. The array is stored in a config file.
I then run the code from the command line with node cli.js testAllCards.
However when I run it, I get testAllCards has been run before all most promises have resolved.
I am obviously missing something here, but can't seem to figure out what it is.
cli.js
const testAllCards = () => {
return controller.testAllCards(config.get('CARD_NUMBERS'))
.then((obj) => {
console.log('testAllCards has been run');
})
.catch((e) => {
console.log('testCards has been run with an error!');
const _err = new ErrHandler(e, eTopicName, eSnsSubject);
_err.handle()
.then(() => {
console.log('Error has been sent with success to sns');
});
});
};
switch(process.argv[2]) {
case 'testAllCards':
testAllCards();
break;
default:
console.log('Please run with `testAllCards`');
controller.js
//Tests response from API for different cards
const testCard = (cardNum) => {
return new Promise((resolve, reject) => {
const expMonth = new Date().getMonth() + 1;
const expYear = new Date().getFullYear() + 2;
const cardObj = {
cardNum: cardNum,
expMonth: expMonth,
expYear: expYear
};
let apiCardItem = '';
return testRequestToApi('getStripeToken', 200, 299, cardObj)
.then((cardItem) => {
return testRequestToApi('postNewCard', 200, 299, JSON.parse(cardItem.body));
})
.then((apiCard) => {
apiCardItem = apiCard.body;
try {
apiCardItem = JSON.parse(apiCardItem);
} catch(e) {
console.log(e);
}
return testRequestToApi('sampleAddToCart', 200, 299);
})
.then(() => {
return testRequestToApi('useFailingStripeCards', 400, 499, apiCardItem.id);
})
.then(() => {
return testRequestToApi('deleteCard', 200, 299, apiCardItem.id);
})
.then(() => {
resolve();
})
.catch((e) => {
reject(e);
});
});
};
//Loops through the card numbers and runs the test command against them
Controller.testAllCards = (cardsArray) => {
const items = cardsArray.map((cardNum) => {
return testCard(cardNum);
});
return Promise.all(items);
};
module.exports = Controller;
test-request-to-api.js
'use strict';
const checkStatus = require('./../utils/status-code-checker');
const formHeaders = require('./../utils/form-req-headers');
const request = require('request');
const expObj = {};
//#requestType {string} - defines which headers and function name to use
//#item {object} - defines item that is being used
expObj.testRequestToApi = (requestType, lowerLimit, upperLimit, item) => {
return new Promise((resolve, reject) => {
const reqOps = formHeaders[requestType](item);
request(reqOps, (err, response, body) => {
if (err) {
const badRequest = {
ErrorMessage: err,
FuncName: requestType,
InternalError: true
};
return reject(badRequest);
}
if (!checkStatus.checkRangeStatusCode(response.statusCode, lowerLimit, upperLimit)) {
console.log(JSON.stringify(body, null, 2));
// Set a bad Status error object
let badStatus = {
StatusCode: response.statusCode,
ErrorMessage: body,
FuncName: requestType,
InternalError: false
};
return reject(badStatus);
}
// console.log(response.headers);
// console.log(body);
const resObj = {
headers: response.headers,
body: body
};
// console.log(`******** ${requestType} *********`);
// console.log(resObj);
// console.log('----------------------------------');
return resolve(resObj);
});
});
};
module.exports = expObj;
Understanding that new Promise() is used only ever necessary when promisifying a callback based API, changing to request-promise and returning my promises in cli.js solved my issue. The execution flow was correctly maintained in this manner.
Changes to the following files are as followed:
cli.js
const testAllCards = () => {
return controller.testAllCards(config.get('CARD_NUMBERS'))
.then((obj) => {
console.log('testAllCards has been run');
})
.catch((e) => {
console.log(e)
console.log('testCards has been run with an error!');
const _err = new ErrHandler(e, eTopicName, eSnsSubject);
return _err.handle()
.then(() => {
console.log('Error has been sent with success to sns');
})
.catch((e) => {
console.log('Failed to publish to sns');
console.log(e);
});
});
};
test-request-to-api
'use strict';
const checkStatus = require('./../utils/status-code-checker');
const formHeaders = require('./../utils/form-req-headers');
const rqp = require('request-promise');
const expObj = {};
//#requestType {string} - defines which headers and function name to use
//#item {object} - defines item that is being used
expObj.testRequestToApi = (requestType, lowerLimit, upperLimit, item) => {
const reqOps = formHeaders[requestType](item);
return rqp(reqOps)
.then((response) => {
if (!checkStatus.checkRangeStatusCode(response.statusCode, lowerLimit, upperLimit)) {
console.log(JSON.stringify(response.body, null, 2));
// Set a bad Status error object
return {
StatusCode: response.statusCode,
ErrorMessage: response.body,
FuncName: requestType,
InternalError: false
};
}
// console.log(response.headers);
// console.log(response.body);
const resObj = {
headers: response.headers,
body: response.body,
previousItem: item
};
// console.log(`******** ${requestType} *********`);
// console.log(resObj);
// console.log('----------------------------------');
return resObj;
})
.catch((e) => {
return {
ErrorMessage: e,
FuncName: requestType,
InternalError: true
};
});
};
module.exports = expObj;
controller.js
//Tests response from API for different cards
Controller.testCard = (cardNum) => {
const expMonth = new Date().getMonth() + 1;
const expYear = new Date().getFullYear() + 2;
const cardObj = {
cardNum: cardNum,
expMonth: expMonth,
expYear: expYear
};
let apiCardItem = '';
return testRequestToApi('getStripeToken', 200, 299, cardObj)
.then((cardItem) => {
return testRequestToApi('postNewCard', 200, 299, JSON.parse(cardItem.body));
})
.then((apiCard) => {
apiCardItem = apiCard.body;
try {
apiCardItem = JSON.parse(apiCardItem);
} catch(e) {
console.log('Already a JSON object -----> Moving on');
}
return testRequestToApi('sampleAddToCart', 200, 299);
})
.then(() => testRequestToApi('useFailingStripeCards', 400, 499, apiCardItem.id))
.then(() => testRequestToApi('deleteCard', 200, 299, apiCardItem.id));
};
//Loops through the card numbers and runs the test command against them
Controller.testAllCards = (cardsArray) => {
return Promise.all(cardsArray.map((cardNum) => {
return Controller.testCard(cardNum);
}));
};
module.exports = Controller;
I rewrote your "testCard" function (controller.js)
//Tests response from API for different cards
const testCard = (cardNum) => {
return new Promise((resolve, reject) => {
let apiCardItem = '';
const expDate = new Date();
const cardObj = {
cardNum: cardNum,
expMonth: expDate.getMonth() + 1,
expYear: expDate.getFullYear() + 2
};
testRequestToApi('getStripeToken', 200, 299, cardObj)
.then((cardItem) => testRequestToApi('postNewCard', 200, 299, JSON.parse(cardItem.body)))
.then((apiCard) => {
apiCardItem = apiCard.body;
try {
apiCardItem = JSON.parse(apiCardItem);
} catch(e) {
console.log(e);
}
return testRequestToApi('sampleAddToCart', 200, 299);
})
.then(() => testRequestToApi('useFailingStripeCards', 400, 499, apiCardItem.id))
.then(() => testRequestToApi('deleteCard', 200, 299, apiCardItem.id))
.then(resolve)
.catch(reject);
});
};
And your "testRequestToApi" (test-request-to-api.js)
expObj.testRequestToApi = (requestType, lowerLimit, upperLimit, item) => {
return new Promise((resolve, reject) => {
const reqOps = formHeaders[requestType](item);
request(reqOps, (err, response, body) => {
let badStatus = {};
let badRequest = {};
let resObj = {};
if (err) {
badRequest = {
ErrorMessage: err,
FuncName: requestType,
InternalError: true
};
reject(badRequest);
return false;
}
if (!checkStatus.checkRangeStatusCode(response.statusCode, lowerLimit, upperLimit)) {
console.log(JSON.stringify(body, null, 2));
// Set a bad Status error object
badStatus = {
StatusCode: response.statusCode,
ErrorMessage: body,
FuncName: requestType,
InternalError: false
};
reject(badStatus);
return false;
}
resObj = {
headers: response.headers,
body: body
};
resolve(resObj);
});
});
};
I think the problem is when you return from a promise before a resolve/reject is getting called.
Also check that in nested promises you can pass resolve/reject to .then/catch for brevity.

Resources