nodejs promise best way to implement from settimeout - javascript

I have the following functions working in nodejs, but I am using a setTimeout rather than a promise. If the createchange takes longer than the timeout I have, my code fails but does not catch the error correctly.
How would I substitute or change the following function(s) to work with a promise, so deploychange waits for createchange to complete, before continuing through the code?
I've tried a couple things but nothing seems to work. Not sure which function I should redo either for the most effective solution.
Any help would be appreciated.
First function
function createchange(accessToken){
const data = {
templateName: "Template 1",
summary: "Deploy Change",
configurationItems: [
config_item
],
wasEnvUsedForTesting: false,
environment: test_env
};
rp({
url: dbConfig.cmas_url,
resolveWithFullResponse: true,
method: 'POST',
json: true,
auth: {
bearer: accessToken
},
body: data,
headers: {
'Content-Type': 'application/json',
'apikey': dbConfig.consumer_key,
},
}, function(err, res) {
if(err){
console.log(err.body);
}else{
console.log(res.body);
crq = res.body.changeid;
}
});
}
2nd function
function run() {
deploychange();
setTimeout(function(){ deployinsert(); }, 7500);
deployrun();
}
3rd function
function deploychange (callback) {
if (req.body.deployEnv == "PRD"){
getToken(function(accessToken) {
createchange(accessToken);
})};
}

According to the request-promise documentation, rp returns a promise.
You can actually convert your createChange function to return a promise like so:
const createchange = accessToken => {
const data = {
templateName: 'Template 1',
summary: 'Deploy Change',
configurationItems: [config_item],
wasEnvUsedForTesting: false,
environment: test_env
};
return rp({
url: dbConfig.cmas_url,
resolveWithFullResponse: true,
method: 'POST',
json: true,
auth: {
bearer: accessToken
},
body: data,
headers: {
'Content-Type': 'application/json',
apikey: dbConfig.consumer_key
}
});
};
You can then call your function with the await keyword.
await createchange(accessToken);
Make sure that the function using await is marked with async
You can also write it like this:
createchange(accessToken)
.then(({changeId}) => {
// Do someth with the changeId
})
.catch(/* Error handling */)

Related

Return full data on JavaScript Promise for a function within a class while using node-client-ntlm

I have a function within a class that makes a call and returns a promise object with data. I do get the data back the issue is I cannot figure out how to make the call wait till all of the data is returned at the moment it only returns a few lines of data and cuts off the rest of the return.
async callCurl(postFields) {
this.postFields = postFields;
const response = await client
.request(
{
url: this.url,
method: "POST",
debug: true,
body: "folderGuid=" + this.postFields,
headers: {
"content-type": "application/x-www-form-urlencoded",
},
resolve: true,
},
"username",
"password",
"",
"domain"
)
.then((response) => {
console.log(response.body);
})
.catch(function (error) {
console.log(error);
});
//return response;
}

Performing POST method Using Axios and Pipe Function

So I am currently learning about FP and the use of the Pipe operator which combines n functions and simply calls it from left to right. Currently, I am trying to make a POST call using Axios and then handle the data returned appropriately, but then the pending promise value always results to undefined. Here is what my code looks like.
The pipe function
const pipe = (...fns) => (initValue) => fns.reduce((v, f) => f(v), initValue)
Here is the first function that is passed to the pipe function
const dataToPost = ({ title, body, userId }) => {
return {
method: 'post',
url: 'https://jsonplaceholder.typicode.com/posts',
data: {
title,
body,
userId,
},
headers: {
'Content-type': 'application/json; charset=UTF-8',
},
}
}
Here is how I implement the pipe function passing it the various arguments
const postTodoFunc = ({ pipe }) => {
return async function postTodo({ title, body, userId }) {
const callJSONAPI = pipe(dataToPost, axios, output) ///this line here
const calledFunc = await callJSONAPI({
title,
body,
userId,
})
return calledFunc
}
}
The output function looks like this.
const output = (response) => {
return response.data
}
The postTodoFunc is invoked like this
const postedTodo = postTodoFunc({ pipe })
const result = postedTodo({
title: 'Rule the world',
body: 'some random body',
userId: 1,
})
console.log(result) // undefined
Now from my understanding, the dataToPost function is called first which returns an object that is equivalent to this
{
method: 'post',
url: 'https://jsonplaceholder.typicode.com/posts',
data: {
title,
body,
userId,
},
headers: {
'Content-type': 'application/json; charset=UTF-8',
},
}
This object is then passed to axios which is then equivalent to the following format
axios({
method: 'post',
url: 'https://jsonplaceholder.typicode.com/posts',
data: {
title,
body,
userId,
},
headers: {
'Content-type': 'application/json; charset=UTF-8',
},
})
The response from this axios call returns undefined. Because I thought the response will be passed to the next function which is this case output function. But that does not seem to be the case. How can I fix this and get the correct data? Initially from the JSONPlaceholder website, the response is meant to be like this
{
id: 101,
title: 'Rule the world',
body: 'Some random body',
userId: 1
}
but then again, I am getting undefined after the pending promise.

Unit test for function returning Promise

Hi I have following function returning promise
module.exports.getJwtToken = async() => {
const httpSearchAddressUXConfig = {
headers: {
Accept: 'application/json',
mock: false,
'Content-Type': 'application/json',
},
data: reqBody,
method: 'POST',
url: `${config.app.entTokens.host}`, // need to get from env variables
timeout: config.app.enterpriseHTTPTimeout
};
try {
const token = await axios(httpSearchAddressUXConfig);
return token.data;
} catch (err) {
throw err;
}
I have following test case which fails with unhandled Promise rejection error
it('should find Jwt token ', async(done) => {
const actualTokenfound = jwtTokenService.getJwtToken();
return actualTokenfound
.then(result => expect(result).toBe(Object))
.then(done);
});
Any Suggestions ?
If you define a async function, you don't need to use "done". I guess something like this it'll works.
it('should find Jwt token ', async () => {
const actualTokenfound = await jwtTokenService.getJwtToken();
expect(result).toBe(Object));
});

Node + ES6: How to use Promise.all with async requests?

I have a method called fetchMerchantData which calls 3 other async methods. I'm trying to use Promise so that it doesn't call resp.direct(301, ...) until all the requests are finished but it's not working.
function fetchOauth2Token(authorizationCode, resp) {
...
request({
url: `https://connect.squareup.com/oauth2/token`,
method: "POST",
json: true,
headers: oauthRequestHeaders,
form: oauthRequestBody,
}, (error, oauthResp, body) => {
if (body.access_token) {
Promise.resolve(fetchMerchantData(body.access_token, body.merchant_id)).then(() => {
console.log("last!"); //<--------------------- this is printing first
resp.redirect(
301,
`myurl.com/blah`
);
});
;
} else {
// TODO find out what to do on failure
resp.redirect(301, `myurl.com/?error=true`);
}
})
}
function fetchMerchantData(access_token, merchant_id){
const updates = {};
request({
url: `https://connect.squareup.com/v1/me/locations`,
method: "GET",
json: true,
headers: {
Authorization: `Bearer ${access_token}`,
Accept: 'application/json',
"Content-Type": "application/json",
},
}, (error, response) => {
if (!error) {
const locations = response.body;
Promise.all([
saveMerchant(merchant_id, access_token, locations),
saveLocations(merchant_id, locations),
installWebhookForLocations(access_token, locations),
]).then(values => {
console.log("first!"); //<--------------------- this is printing last
return Promise.resolve("Success");
})
}
});
}
And here's an example of the saveMerchant method which calls firebase:
function saveMerchant(merchant_id, access_token, locations) {
const merchantRef = database.ref('merchants').child(merchant_id);
const location_ids = locations.map(location => location.id);
merchantRef.update({
access_token,
location_ids,
});
}
How would I synchronize this?
== UPDATE ==
This is how my installWebhookForLocations method looks:
function installWebhookForLocations(access_token, locations){
const locationIds = locations.map(location => location.id);
locationIds.forEach((locationId) => {
request({
url: `https://connect.squareup.com/v1/${locationId}/webhooks`,
method: "PUT",
json: true,
headers: {
Authorization: `Bearer ${access_token}`,
Accept: 'application/json',
"Content-Type": "application/json",
},
body: ["PAYMENT_UPDATED"],
}, (error) => {
if (!error){
console.log(`Webhook installed for ${locationId}`);
}
});
});
}
Here is an example of saveMerchant that would use a promise.
function saveMerchant(merchant_id, access_token, locations) {
return new Promise(function (resolve, reject) {
const merchantRef = database.ref('merchants').child(merchant_id);
const location_ids = locations.map(location => location.id);
merchantRef.update({
access_token,
location_ids,
}, function (error) {
if (error) return reject(error);
resolve();
});
});
}
To make the above easier, there is a nice Promise library called Bluebird, it has a promisify utility, that you could apply to firebird update method.
Also for your second question were your using forEach, bluebird has a nice utility function called map that you could use instead.

Cannot keep user session alive on protractor test

I am using Protractor for e2e testing on my Application.
STORY: For a specific use case I need to make sure the number of items on a table matches the API response. I read that I can use the 'request' to make http calls and retrieve the information. I need to be an authenticated user in my browser session to retrieve the information.
PROBLEM: After sucessfully logging in, I try to fetch the items list, but get a 401 response ('no user session available').
Some material:
var request = require('request');
var querystring = require('querystring');
app.createSession = function() {
var formData = querystring.stringify({
email: browser.params.user.admin.email,
password: browser.params.user.admin.password
});
request({
url: "https://MY_API_DOMAIN/auth",
method : 'POST',
headers: [
{
name: 'Accept',
value: 'application/x-www-form-urlencoded'
}
],
body: formData
}, function(err, response, body) {
console.log('FIRST:', body); //returning 200 ALL FINE
request({
url: "https://MY_API_DOMAIN/api/v1/auth",
method : 'GET',
withCredentials: true,
headers: [{
name: 'Accept',
value: 'application/json'
}]
}, function(err, response, body) {
console.log('SECOND:', body); //returning 401
});
});
};
If you need more info please let me know. When I simulate a a login on my HTML with Selenium, all works fine and the items are being fetched. The problem is when processing the HTTP request inside my helper function.
You can use Protractor promises and controlFlow in order to turn async calls into sequential execution and force framework to wait until all promises are resolved and the flow is complete. In order to achieve this all async function will have to return a promise that will be solved later.
The code will become:
it ("expect to call all functions", function() {
createSession = function() {
var defer = protractor.promise.defer();
var formData = querystring.stringify({
email: browser.params.user.admin.email,
password: browser.params.user.admin.password
});
request({
url: "https://MY_API_DOMAIN/auth",
method : 'POST',
headers: [
{
name: 'Accept',
value: 'application/x-www-form-urlencoded'
}
],
body: formData
}, function(err, response, body1) {
console.log('FIRST:', body1); //returning 200 ALL FINE
request({
url: "https://MY_API_DOMAIN/api/v1/auth",
method : 'GET',
withCredentials: true,
headers: [{
name: 'Accept',
value: 'application/json'
}]
}, function(err, response, body2) {
defer.fulfill({body1: body1, body1: body2});
//or defer.reject()
console.log('SECOND:', body2); //returning 401
});
});
return defer.promise;
};
var flow = protractor.promise.controlFlow();
flow.execute(createSession);
flow.execute(function(){
console.log("All requests were resolved");
})
});

Categories

Resources