Novice friendly way of calling two functions sequentially in JS - javascript

Sorry to ask a question that seems to have been answered at length in countless ways, I understand the asynchronous nature of JS, but the countless treatises on promises and callbacks I've read hasn't helped me produce working code.
I have 2 functions that interact with an API, and I just want to be able to call them in a way where one will run after the other.
These are my two functions:
let pveNextid = "";
function getNextID() {
var clientServerOptions = {
method: 'GET',
uri: apiRoot + "/cluster/nextid",
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': pveCookie,
}
}
request(clientServerOptions, function(error, response) {
pveNextid = JSON.parse(response.body).data;
console.log("Next VMID: " + pveNextid);
})
}
// Create a new container with specs defined in conf.js
function newContainer() {
var clientServerOptions = {
method: 'POST',
uri: apiRoot + "/nodes/" + conf.pveNode + "/lxc",
form: {
net0: "bridge=vmbr0,name=eth0,ip6=auto",
ostemplate: conf.pveTemplate,
vmid: pveNextid,
unprivileged: 1,
storage: "local-lvm",
memory: 320,
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': pveCookie,
'CSRFPreventionToken': pveCSRF,
}
}
request(clientServerOptions, function(error, response) {
console.log(response.body);
})
};
There must be a simple, as in a few readable lines, way of doing this?

The simplest way would be to provide a callback to the functions to give you a hook to run some code after the request completes, you can get rid of the global variable too this way:
// Take a callback here
function getNextID(callback) {
var clientServerOptions = {
method: 'GET',
uri: apiRoot + "/cluster/nextid",
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': pveCookie,
}
}
request(clientServerOptions, function(error, response) {
var pveNextid = JSON.parse(response.body).data;
console.log("Next VMID: " + pveNextid);
// call the callback and give it the information you want to provide to the function
callback(pveNextid);
})
}
// Create a new container with specs defined in conf.js
// take the pveNextid here
function newContainer(pveNextid) {
var clientServerOptions = {
method: 'POST',
uri: apiRoot + "/nodes/" + conf.pveNode + "/lxc",
form: {
net0: "bridge=vmbr0,name=eth0,ip6=auto",
ostemplate: conf.pveTemplate,
vmid: pveNextid,
unprivileged: 1,
storage: "local-lvm",
memory: 320,
},
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': pveCookie,
'CSRFPreventionToken': pveCSRF,
}
}
request(clientServerOptions, function(error, response) {
console.log(response.body);
})
};
// call getNextId and provide the callback here that you want to run after the first request
getNextId(newContainer);
I'd suggest promises and async/await and other more maintainable solutions over callbacks all the way down, however in this case it is a simple solution.

Related

Trustpilot Authentication Error Unknown grant_type

I want to use Trustpilot API to send email review invitation. Before making that call, I need to get an access token. I'm following Trustpilot's documentation in the function below. I keep getting this error of Unknown grant_type. According to the documentation, it is supposed to be set to "password" to get the token and it is not working. I tried this solution but it is not working for me. I can't seem to know what's causing the error especially that it is very general.
trustPilot.getAuthToken = async () => {
let apiKey = process.env.TRUSTPILOT_API
let secrect = process.env.TRUSTPILOT_SECRET
let baseEncoded = Buffer.from(`${apiKey}:${secrect}`).toString('base64')
console.log(baseEncoded, 'base')
let authToken = null
try {
authToken = await axios({
method: 'POST',
url: `https://api.trustpilot.com/v1/oauth/oauth-business-users-for-applications/accesstoken`,
headers: { Authorization: 'Basic ' + baseEncoded, 'Content-Type': 'application/x-www-form-urlencoded' },
content: `grant_type=password&username=${process.env.TRUSTPILOT_EMAIL}&password=${process.env.TRUSTPILOT_PASSWORD}`,
})
console.log(authToken, 'auth')
} catch (error) {
console.log(error.response, 'err')
throw { code: '404' }
}
return authToken
}
Please take a look at axios documentation. You are passing content: instead of data:. Axios call should be like this:
authToken = await axios({
method: 'POST',
url: `https://api.trustpilot.com/v1/oauth/oauth-business-users-for-applications/accesstoken`,
headers: { Authorization: 'Basic ' + baseEncoded, 'Content-Type': 'application/x-www-form-urlencoded' },
data: `grant_type=password&username=${process.env.TRUSTPILOT_EMAIL}&password=${process.env.TRUSTPILOT_PASSWORD}`,
})

nodejs promise best way to implement from settimeout

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 */)

How do I pass the response of one API as a request param in another API using Request-Promise

I want to pass the response received from one API as a request parameter in another API using Request-Promise NodeJs module. Can someone pls help me in this? I am giving a brief of the sample code below:
var Sequence = {
test1: function (param) {
return request({
"method": "POST",
"uri": baseURL+"/v1/" + userID + "/test/info/",
"json": true,
"headers": {
"Accept": "application/json",
},
}).then(function (result) {
return result.pairingInfo // I want to use this pairinfInfo param in another request
})
test2 : function (param) {
return request({
"method": "POST",
"uri": baseURL+"/v1/passenger/" + userID + "/test/test/",
"json": true,
"headers": {
"Accept": "application/json",
},
"qs": {
**"pairingInfo": pairingInfo**,//This pairingInfo would come from the returned result.pairingInfo of test 1 API call
}
})
}
},
How can I achieve this?
You can use this because you have a return statement in the test1() method. So, just trigger it to get it:
"qs": {
"pairingInfo": this.test1(),
}
Sequence.test1(param)
.then(function(pairingInfo) {
Sequence.test2(pairingInfo) ;
});
// You are returning the paringInfo with the first promise, so you can use it in the .then() method.
Use this function:
const sequence = async (baseURL, userID) => {
try {
let options1 = {
method: 'POST',
uri: baseURL + '/v1/' + userID + '/test/info/',
json: true,
headers: {
Accept: 'application/json'
}
};
let pairingInfo = await request(options1);
if (pairingInfo) {
let options2 = {
method: 'POST',
uri: baseURL + '/v1/passenger/' + userID + '/test/test/',
json: true,
headers: {
Accept: 'application/json'
},
qs: {
pairingInfo: pairingInfo //This pairingInfo would come from the returned result.pairingInfo of test 1 API call
}
};
await request(options2);
return true;
} else {
console.log('Request 1 failed');
return false;
}
} catch (err) {
console.error(err);
return false;
}
};

Working with OfflineJS and AngularJS

I am working on an angular app where I want to integrate OfflineJS functionality.
I have created a general service for getting and posting data to/from an API,and a specific service for each module.
Here is the code
app.service('MethodProvider', function ($http) {
var self = this;
self.get = function (url) {
var obj = {
url: url,
method: 'GET',
async: true,
headers: {
'Content-Type': 'application/json'
}
};
return $http(obj);
};
self.post = function (url, data) {
var obj = {
url: url,
method: 'POST',
async: true,
data: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
}
};
return $http(obj);
};
self.put = function (url, data) {
var obj = {
url: url,
method: 'PUT',
async: true,
headers: {
'Content-Type': 'application/json'
}
};
if (typeof data != 'undefined' && data != null) {
obj.data = JSON.stringify(data);
}
return $http(obj);
};
self.delete = function (url) {
var obj = {
url: url,
method: 'POST',
async: true,
headers: {
'Content-Type': 'application/json'
}
};
return $http(obj);
};
return self;
});
And a specific module service like User module
app.service('UserSrvc', function (MethodProvider) {
var self = this;
self.create = function (data) {
var url = apiUrl + '/user/add';
return MethodProvider.post(url, data);
};
return self;
});
How do I integrate OfflineJS in this code , I want to intercept HTTP request when network connectivity is down and resume requests when network connectivity is up . I have studied this example but unable to integrate this in angular need an example to get started.
hope this helps the future users:
Offlinejs adds Offline object to the global window object.
Offlinejs does not trigger check() by itself (it does it once if checkOnLoad option is set to true).
You may call Offline.check() just before you make an ajax request to your server and check for connection.
You can also do polling, if your app is xhr intensive.
var run = function(){
if(Offline.state=="up")
Offline.check();
};
setInterval(run, 20000); // check after 20sec
Offline.on('down',function(){ /**code to handle network down*/ });
As pointed by #Adnan Umer You need to set Offline.options = { interceptRequests: true, requests: true }
to intercept failed requests and try again once connection is back.
One caveat here is that the requests resent by Offline will be out of the scope of Angular, accordingly, all the GET requests will result to nothing. Which is actually fine, usually the user initiates the get requests.
Offline.options = {
checks: {xhr: {url: "put_url_to_check_status_of_your_server"}}
}
By default, Offlinejs checks for favicon.ico.

Node / Javascript - pipe writeStream / file to post request

I have the following code, it creates a file on a remote server from a test var (just to make sure it worked), but now I need to upload a file and I'm not sure how to actually attach it to the request, here is the code:
var dataString = '#test.txt';
var options = {
uri: 'https://site.zendesk.com/api/v2/uploads.json?filename=test.txt',
method: 'POST',
headers: {
'Content-Type': 'application/binary',
'Accept': 'application/json',
Authorization: 'Basic bXVydGV6LmF....'
},
body: dataString
//this will create a test file with some text, but I need
//to upload a file on my machine instead
}
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
}
var x = {
error: error,
response: response,
body: body
}
console.log(x);
}
request(options, callback);
I was thinking something in the lines of:
fs.createReadStream('text.txt').pipe({function?})
But I'm not sure how to finish this part unfortunately.
update: 2019
It's been a LONG time, but someone asked for the solution. I'm not sure if this is how I fixed it tbh or if this code even works, but I found this digging around, give it a try.
Also, Zendesk updated their API at some point, not sure when exactly so this may be old anyways:
var uploadAttachment = function() {
var uOptions = {
uri: 'xxx/api/v2/uploads.json?filename=' + fileName,
method: 'POST',
headers: {
'Content-Type': 'application/binary',
'Accept': 'application/json',
Authorization: 'Basic xxx'
}
};
function callback(error, response, body) {
if (!body) {
if (error) {
return next(error);
} else {
var x = {
error: true,
message: "Some message",
err: response
};
return next(x);
}
}
if (body && body.error) {
return next(error);
}
if (error) {
return next(error);
}
var jr = JSON.parse(body);
var uploaded = {};
if (jr.upload) {
uploaded = jr.upload;
}
attachToComment(uploaded);
}
fs.createReadStream(tempPath + fileName).pipe(request(uOptions, callback));
};
I hope this helps, sorry in advance if it does not work, I no longer have access to zendesk.

Categories

Resources