Make a synchroneous request in NodeJS - node.js

I am trying to make a post request using NodeJS and request.
I tried using promises and the async/await like other post says but I can manage to make work.
const express = require('express');
const bodyParser = require('body-parser');
var request = require("request");
const app = express();
app.use(bodyParser.json());
var token = '';
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
function postRequest(options) {
request(options, function (error, response, body) {
if (error) throw new Error(error);
token = (JSON.parse(body)).access_token;
console.log(token + 'tet');
return (token);
});
}
async function requestToken() {
var options = {
method: 'POST',
url: 'https://simplivity#xxxx/api/oauth/token',
headers: { 'Content-Type': 'application/json' },
formData:
{
grant_type: 'password',
username: 'administrator#vsphere.local',
password: 'xxxx'
}
};
try {
var test = await postRequest(options)
return (test);
} catch (error) {
console.error(error);
}
}
var test = requestToken();
console.log(test + 'TOT');
This is the answer :
[object Promise]TOT
00bd0beb-8967-4534-8c63-2e5d0d6876d4tet
Which should be the opposite.
thank you for your help.

(async () => {
var test = await requestToken();
console.log(test + 'TOT');
})();
While not very tidy something like this should work.
Better:
requestToken()
.then(response => {
console.log(response);
});

You need to return a promise.
Change your postRequest to:
function postRequest(options) {
return new Promise(function(resolve, reject) {
request(options, function (error, response, body) {
if (error) throw new Error(error);
token = (JSON.parse(body)).access_token;
console.log(token + 'tet');
resolve(token);
});
});
}

Related

Api to accept written number as option?

I have using azcapture api which only accepts number as id at the end of 'path' Options of Fetch/Request api and works when I type in the id e.g.
Var options = {
'path':'url+key+1234455
}
When 1234455 is typed like above it works. But since this is the resp I cannot beforehand know the id so I pass it from the req result which was a POST and now I do a GET, effectively I have chained them without using Promises:
Function secondCall(id)
Console.log (id)
Var options = { 'path': url+key+id
}
This above always fails even if I parse id with parseInt or Number () or if I parse or coerce then
id.toString()
since ClientRequestArgs.path is a string (ClientRequestArgs.path?: string), I believe, it always resolves to a string.
Am I seeing double here or is there a fundamental issue?
POSTMAN works fine btw and the code I have below is exported from POSTMAN except in chainResolve function the first 4 lines are my conversion code.
If I change this line and replace the resolvedID to a pre generated id it will work:
url: 'http://azcaptcha.com/res.php?key=kowg1cjodmtlyiyqheuzjfzta4ki0vwn&action=get&id=335439890',
But as resolvedID the converted string (pre generated id) into an int it won't work.
Full code with keys omitted:
var request = require('request');
var fs = require('fs');
var http = require('follow-redirects').http;
var axios = require('axios');
var options = {
'method': 'POST',
'url': 'http://azcaptcha.com/in.php?key=key&method=post',
'headers': {
},
formData: {
'file': {
'value': fs.createReadStream('C:/Users/jsonX/Documents/fiverr/captchatest.png'),
'options': {
'filename': 'C:/Users/jsonX/Documents/fiverr/captchatest.png',
'contentType': null
}
}
}
};
//let respondedID;
convertToInt = (x) => {
var converted=parseInt(x[1], 10);
return converted;
}
request(options, function (error, response) {
if (error) throw new Error(error);
var respondedID = response.body;
console.log('line 26 '+respondedID);
chainResolve(respondedID);
});
chainResolve = (id) => {
var sid = id.split('|');
var resolvedID=parseInt(sid[1], 10)
console.log(parseInt(sid[1], 10));
console.log('line 40 '+convertToInt(sid));
var config = {
method: 'get',
url: 'http://azcaptcha.com/res.php?key=key&action=get&id=resolvedID',
headers: { }
};
axios(config)
.then(function (response) {
console.log(JSON.stringify(response.data));
})
.catch(function (error) {
console.log(error);
});
}
Solved it! It turns out this API will not give you back any result if the resp is CAPTCHA_NOT_READY. So the solution was to set a timeout and push this with a callback in my response block of the second request:
axios(config)
.then(function (response) {
if (result === 'CAPCHA_NOT_READY'){
console.log('Captcha is being processed');
var startTime = setTimeout(function() {
waitR(id);
clearTimeout(startTime);
},5000);
} else {
console.log(result.split('|')[1]);
}
})
.catch(function (error) {
console.log(error);
});
waitR = (id) => {
console.log('The result is being processed ...');
chainResolve(id);
}

get data to index.js(modul.export)

I am new in Node.js.
I'm trying to figure out how I can get values from file auth.js to index.js with module.export.
File auth.js:
const request = require('request');
request.post(
'http://192.167.1.118/api/v1/auth/request',
{
form: {
application: 'car',
user: 'car',
},
},
(error, res, body) => {
if (error) {
console.error(error);
return;
}
//console.log(`statusCode: ${res.statusCode}`)
body = JSON.parse(body);
//console.log(body);
}
);
module.exports.request = request;
File index.js:
const aaa = require('./auth');
console.log(aaa.request);
You may need to convert that callback based request into promise.
Make an individual function which returns promise of you api response.
auth.js
const request = require('request');
const sendRequest = () =>
new Promise((resolve, reject) =>
request.post(
'http://192.167.1.118/api/v1/auth/request',
{
form: {
application: 'car',
user: 'car',
},
},
(error, res, body) => {
if (error) {
reject(error);
}
body = JSON.parse(body);
resolve(body);
}
)
);
module.exports.request = sendRequest;
index.js
const { request } = require('./auth');
request().then(body => {
console.log(body);
}).catch(error => {
console.error(error); // <- error
});

How can I send the response.body out of request module function?

I started by creating a return statement in the request function (I have linked a picture) and then console.log it outside of the function but that didn't work out.
My server code
var options = {
'method': 'POST',
'url': 'http://localhost:8080/ES_Part1/api/user/getUser',
'headers': {
'Content-Type': 'application/x-www-form-urlencoded'
},
form: {
'username': username,
'password': password
}
};
requestToApi(options, function(error, response) {
if (error) throw new Error(error);
console.log("Send form data to remote api and to return the user from Spring")
console.log(response.body);
return response.body
});
var fromapi = response.body;
res.end();
Example:
I suggest you use a Promise-based approach here rather than the callback-style that you're using for requestToApi. If you're using the request package, there is a Promise-based version available.
Alternative solution would be to create a promise yourself, like such:
var requestToApiAsPromise = (options) => {
return new Promise((resolve, reject) => {
requestToApi(options, (error, response) => {
if (error) {
reject(error)
return
}
resolve(response.body)
})
})
}
Then you can use this method in your middleware:
app.post("/checkUser", (req, res) => {
async function process() {
try {
var username = req.body.username
var password = req.body.password
var options = {...}
var response = await requestToApiAsPromise(options)
// response => response.body
// do whatever
res.end()
} catch (error) {
next(error)
}
}
process()
})
This method uses async/await so that it lets you write your code as if you were doing things synchronously, so it's making it easier to make asynchronous calls and have them "wait" before the next line gets executed.
👨‍🏫 If you want to get respose.body outside the handler, than you can use this code below 👇:
// an example get function
app.get('/users', async(req, res) => {
var options = {
'method': 'POST',
'url': 'http://localhost:8080/ES_Part1/api/user/getUser',
'headers': {
'Content-Type': 'application/x-www-form-urlencoded'
},
form: {
'username': username,
'password': password
}
};
const result = new Promise((resolve, reject) => {
requestToApi(options, function(error, response) {
if (error) return reject(error);
return resolve(JSON.parse(response.body));
});
})
// make sure, to use async in your function
// because we're using await here
var fromapi = await result;
// It's working here
console.log(fromapi);
res.end();
})
That code above 👆, only an example that you can use to read response.body. If you want to handle the error from that code above, you can use like this code below:
try {
// make sure, to use async in your function
// because we're using await here
var fromapi = await result;
// It's working here
console.log(fromapi);
} catch(ex) {
// print error response
console.log(ex.message);
}
I hope it's can help you 🙏.

How to return a string from a node js api call

I have using a code snippet which will return a value after post rest call to an api.
But where ever i am calling the function its not returning the value and prints undefined.
when ever i will call any where getAccessToken(), its says undefiuned, but ifi print the value am getting the output.
How do the called will get the return value, do i need to change anything in the below code.
Thanks
var getAccessToken = exports.getAccessToken = function (res) {
// body...
const request = require('request');
const authKey='EAcEa4o4SkBLo9IpZpW4Y7oDn7d6b30GlouNh28pJ6Q='
const ContentType='application/x-www-form-urlencoded' ;
var postData={
'grant_type':'client_credentials'
};
const options = {
url: 'https://xyz/v1/login',
method: 'POST',
headers: {
'Content-Type': ContentType,
'Authorization':authKey
},
body:require('querystring').stringify(postData)
};
var token;
request(options, function(errror, response, body) {
//console.log(JSON.parse(body));
token= JSON.parse(body).access_token;
});
return token;
}
Your function doesn't return anything. You may use async/await, promises or callbacks to fix it.
exports.getAccessToken = async (res) => {
...
return await request(...)
}
OR
exports.getAccessToken = function(res) {
...
return new Promise(function(resolve, reject) {
...
request(options, function(errror, response, body) {
var token = JSON.parse(body).access_token;
resolve(token);
}
});
}
// Use it like
getAccessToken().then(function(token) { ... });
OR
exports.getAccessToken = function(res, cb) {
...
request(options, function(errror, response, body) {
var token = JSON.parse(body).access_token;
cb(token);
}
}
// Use it like
getAccessToken(res, function(token) { ... });

Authorization issue when downloading AMZ Advertising Report

I have the following app to download productAds from amazons Sponsored Products API
Docs: https://advertising.amazon.com/API/docs/reference/reports
When I try to fun it, I get the response from requesting the report, and obtain a file in an s3 Bucket.
server is running at localhost:3000
{"reportId":"amzn1.clicPI.v1.p7.5B7EE.d141f-e5-4b-a8-6a4e712","status":"SUCCESS","statusDetails":"Report has been successfully generated","location":"https://advertising-api.amazon.com/v1/reports/amzn1.clsAPI.v1.p7.5B7EE.d151f-e5-4b-a8-699e712/download","fileSize":22}
Next I try to download the report
and the repose I get the following erro:
donwloading <?xml version="1.0" encoding="UTF-8"?>
<Error><Code>InvalidArgument</Code><Message>Only one auth mechanism allowed; only the X-Amz-Algorithm query parameter, Signature query string parameter or the Authorization header should be specified</Message><ArgumentName>Authorization</ArgumentName><ArgumentValue>bearer Atza|IwEBIJvCt20TUi122srkN4JCOdUxlBNuLJBrtbIGF9x5QbKG67f-K-0L4RkLzeyouXWy_U_-VscaCe1aFqOJK55X9Mu2X6nwWkAWRyhc6cCMfPjKpyyVjKtPqC8Plme84om1dqtmIqC93yUVc_clHimQqmnl262te2EXyUhYoVQg8hK2nlDG67Iw7xjsLK4rgl3E4RR36DHnZkEOnVQZtfjIkIbcYtsCSAdpRZRazF4FQfpS-jHvMlwuH8TZfY9tRpmBEx5fjJw1WZ14Dejqti23mZ7yt-MjNkUuD-DdPXs3fek1ZJePlHEVzcI2y_WzCnwJnoSVp5a5w1WgNco8YqEGEuLsT9S0dxQRluTiw8f4b4lx2FFFm9jz0K7pqo1Mvs6DZOVCDJzE-xJ_VLlWoE5QDMUAMor4AEQH44_0NWBjJDrYaVvn1vZLCER1uxW4jgr127W5yXaj4y1vj_vADwFq9a3330hAc73EWwL6FFSfoTQZyNc4Fh1d3DXfVHpXFk6cv0bHt4cV_OotGwGHat5fv75VHX5K3al3Xd5-QJv2cTiQ9srY5oqKsdbxptGaxAdrdMQaUlFHhyHEGbwED9xYoCw6-IauN15gvMAei9wz2kzRCA</ArgumentValue><RequestId>BDCE812C4363E9D2</RequestId><HostId>4ixH24mPtMBt+FDnI3rM9UJP95toaNBmmR1v0uQJ5XkyiXbtLEuZ8d+vDI0+gquwhn6/Fkz6/+o=</HostId></Error>
Here is the app. How can I download the report and pass the headers correctly? I found this repo in PHP that has the download function: https://github.com/dbrent-amazon/amazon-advertising-api-php/blob/master/AmazonAdvertisingApi/Client.php
const express = require('express')
const app = express();
const request = require('request');
const moment = require('moment');
const fs = require('fs')
const path = require('path')
const config = require('./config')
const auth = require('./helpers/auth');
const cron = require('./helpers/cron');
const con = require('./helpers/database');
const getProfiles = (headers) => {
return new Promise((resolve, reject) => {
request({
url: config.ad_url + '/v1/profiles',
method: "GET",
headers: headers
}, (err, httpResponse, body) => {
if (err) {
reject(err);
}
resolve(body);
});
})
}
const createReport = (params, recordType, headers) => {
return new Promise((resolve, reject) => {
request({
url: config.ad_url + '/v1/' + recordType + '/report',
method: "POST",
headers: headers,
json: params
}, (err, httpResponse, body) => {
if (err) {
reject(err);
}
resolve(body);
});
})
}
const getReport = (reportId, headers) => {
return new Promise((resolve, reject) => {
request({
url: config.ad_url + '/v1/reports/' + reportId,
method: "GET",
headers: headers
}, (err, httpResponse, body) => {
if (err) {
reject(err);
}
resolve(body);
});
})
}
function download(fileUrl, apiPath, callback) {
var url = require('url'),
http = require('http'),
p = url.parse(fileUrl),
timeout = 10000;
var file = fs.createWriteStream(apiPath);
var timeout_wrapper = function (req) {
return function () {
console.log('abort');
req.abort();
callback("File transfer timeout!");
};
};
console.log('before');
var request = http.get(fileUrl).on('response', function (res) {
console.log('in cb');
var len = parseInt(res.headers['content-length'], 10);
var downloaded = 0;
res.on('data', function (chunk) {
file.write(chunk);
downloaded += chunk.length;
process.stdout.write("Downloading " + (100.0 * downloaded / len).toFixed(2) + "% " + downloaded + " bytes" + isWin ? "\033[0G" : "\r");
// reset timeout
clearTimeout(timeoutId);
timeoutId = setTimeout(fn, timeout);
}).on('end', function () {
// clear timeout
clearTimeout(timeoutId);
file.end();
console.log(file_name + ' downloaded to: ' + apiPath);
callback(null);
}).on('error', function (err) {
// clear timeout
clearTimeout(timeoutId);
callback(err.message);
});
});
// generate timeout handler
var fn = timeout_wrapper(request);
// set initial timeout
var timeoutId = setTimeout(fn, timeout);
}
const recordType = 'productAds';
const campaignType = 'sponsoredProducts';
const reportDate = moment().format('YYYYMMDD');
const metrics = 'campaignId,sku,currency,attributedConversions1d';
const reportParam = {
campaignType: campaignType,
// segment: "query",
reportDate: reportDate,
metrics: metrics
}
auth().then(res => {
const headers = {
'Content-Type': 'application/json',
'Authorization': config.token_type + ' ' + res.access_token,
'Amazon-Advertising-API-Scope': '196354651614',
}
// getProfiles(headers).then(res => {})
const reportId = 'amzn1.clicksAI.1.p.5B057EE.d41f-e5-4a-a8-699e712';
getReport(reportId, headers).then(res => {
console.log(res)
const file = JSON.parse(res);
// console.log(file.location )
// download
request({
url: file.location,
method: 'GET',
headers: {
'Authorization': headers.Authorization,
'Amazon-Advertising-API-Scope': '196335474',
'Allow': 'GET, HEAD, PUT, DELETE'
}
}, (err, response, body) => {
console.log('donwloading', body)
})
})
createReport(reportParam, recordType, headers).then(res => {
const reportId = 'amzn1.clicksI.v1.p7.5B07EE.d1541f-e5-eb-a68-6996e712';
})
})
app.listen(3000, function(err) {
console.log("server is running at localhost:3000");
})
This is caused by sending the "Authorization" header to S3 and it doesn't want that. The reason is because the /download response from the API is a 307 redirect so the client you are using is redirecting with full API headers. To get around this, prevent your client from following redirects and parse the S3 location from the header of the response instead.

Resources