Returning from an API request [duplicate] - javascript

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I have a function that does POST request to get access tokens from an API. The function works insofar as printing the token to the console but I couldn't find a way to parse and save the access-token to a variable for using in other methods.
I've searched a lot about these on Stack Overflow, and one thing I came across was the notion of callbacks, async/await... However there is no concrete answers that show me how to RETURN the value after the request is made.
I'm getting undefined values, probably because my function is executing too fast before the request ends but nonetheless I would like to know a specific code implementation (using another callback function or something different) that allows me to get the value accessible outside these asynchronous functions.
My code is below along with a screenshot. Keep in mind this is a Lambda code for an Alexa skill
function ParseToken(obj) {
var string = obj + "";
return string;
}
function httpRetrieveToken() {
var http = require("https");
var options = {
"method": "POST",
"host": "hostName",
"path": "pathVal",
"headers": {
"content-type": "contentType",
"Authorization": "Bearer token",
"cache-control": "no-cache",
}
};
var req = http.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
var body = Buffer.concat(chunks);
console.log(body.toString());
});
});
req.write("stuff here");
req.end();
}

Parsing token
Once you have the text representing your token object you can use JSON.parse to convert it to an object:
var json = '{"token":"ABCDEFG123456789", "expires":36000}';
obj = JSON.parse(json);
console.log(obj.token);
// expected output: ABCDEFG123456789
Using Callback
You can send a callback function as parameter to the httpRetrieveToken function like:
var http = require("https");
function httpRetrieveToken(cb) {
var options = {
"method": "POST",
"host": "hostName",
"path": "pathVal",
"headers": {
"content-type": "contentType",
"Authorization": "Bearer token",
"cache-control": "no-cache",
}
};
var req = http.request(options, function (res) {
var _cb = cb;
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
var body = Buffer.concat(chunks);
var token = JSON.parse(body.toString());
_cb(token); // Callback function
});
});
req.write("stuff here");
req.end();
}
Then you can use function like:
httpRetrieveToken(function(token) {
// Do something with the token
});
The reason to use a callback function is to execute it once the asynchronous process has been finished, then enclose in that callback the processes to follow with the required data.
Using Promise
Using promise object, you provide a function who executes either resolve when your process was successful or reject when you had an error. Then you set a function to be executed on sucess with then method, where you can use the token retrived by your http request.
var http = require("https");
function httpRetrieveToken() {
var options = {
"method": "POST",
"host": "hostName",
"path": "pathVal",
"headers": {
"content-type": "contentType",
"Authorization": "Bearer token",
"cache-control": "no-cache",
}
};
return new Promise(function(resolve, reject) {
let req = http.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
var body = Buffer.concat(chunks);
var token = JSON.parse(body.toString());
resolve(null, token); // Callback function
});
});
req.on("error", function(err) {
reject(err);
});
});
}
httpRetrieveToken().then((err, token) => {
if(err) console.log(err);
// Do something with token
});

Related

Need to call Two APIs In Loop using node js

I have an array of ssn number and I have two api list in which I need to pass ssn number as request json so I need to call both api inside ssn loop so I pass ssn to json request during call both api but code is not work properly both api call at a time simulteniously, Where I need to call both api one by one.
Both API details and code are as follow
My Code:
let ssn = [460458524, 637625452, 453311896, 635285187, 455791630, 642348377, 463590491, 450730278, 641201851, 379965491];
async function getCRCDetails() {
ssn.forEach(function (item) {
if(item){
let CBCOptions = {
'method': 'POST',
'url': 'https://loanboard.houstondirectauto.com/api/Report',
'headers': {
'Content-Type': 'application/json',
'Cookie': 'ci_session=udmojmlc5tfl3epbrmtvgu6nao2f031p'
},
body: JSON.stringify({
"token": loantoken,
"action": "CBCReport",
"variables": {
ssn: item
}
})
}
request(CBCOptions, function (error, response) {
console.log(item);
console.log("CBCOPtion ", CBCOptions);
if (error) throw new Error(error);
result = (JSON.parse(response.body));
console.log("Result =", result);
CRCReport.push(result);
})
let EmployerInfoOptions = {
'method': 'POST',
'url': 'https://loanboard.houstondirectauto.com/api/Report',
'headers': {
'Content-Type': 'application/json',
'Cookie': 'ci_session=udmojmlc5tfl3epbrmtvgu6nao2f031p'
},
body: JSON.stringify({
"token": loantoken,
"action": "getEmployerInfo",
"variables": {
ssn: item
}
})
}
request(EmployerInfoOptions, function (error, response) {
console.log(response.body);
})
}
Here I need to call API request one by one.Anyone Guide me please.
I prefer use async await method for this situation
you need install and require async and request-promise
after that :
const request = require("request-promise");
const async = require("async");
let ssn = [460458524, 637625452, 453311896, 635285187, 455791630, 642348377, 463590491, 450730278, 641201851, 379965491];
async function getCRCDetails() {
//like a forEache
async.eachSeries(ssn, async (item) => {
let CBCOptions = {
method: "POST",
url: "https://loanboard.houstondirectauto.com/api/Report",
headers: {
"Content-Type": "application/json",
Cookie: "ci_session=udmojmlc5tfl3epbrmtvgu6nao2f031p",
},
body: JSON.stringify({
token: loantoken,
action: "CBCReport",
variables: {
ssn: item,
},
}),
};
let EmployerInfoOptions = {
method: "POST",
url: "https://loanboard.houstondirectauto.com/api/Report",
headers: {
"Content-Type": "application/json",
Cookie: "ci_session=udmojmlc5tfl3epbrmtvgu6nao2f031p",
},
body: JSON.stringify({
token: loantoken,
action: "getEmployerInfo",
variables: {
ssn: item,
},
}),
};
try {
let resultCBCOptions = await request(CBCOptions);
let EmployerInfoOptions = await request(EmployerInfoOptions);
console.log(resultCBCOptions)
console.log(EmployerInfoOptions)
//do pushing resultCBCOptions
//do pushing EmployerInfoOptions
} catch (error) {
console.log(error);
}
},
() => {
console.log("finished");
}
);
}
In Node the request methods that you are using are asynchronous. Meaning the runner (server) that runs the code does not wait for the request to finish and just continues to execute the next lines.
One thing that you can do is,
request.post(params).on("response", function(response) {
//....Do stuff with your data you recieve
// Make the next call here
request.post(params).on("response"), function() {
// Here you will have the second call's results
}
})
This ensures that both the API calls happen in order and only after the first one finishes.
Note:
The request library that you are using has been deprecated back in 2020. See https://github.com/request/request Hence, I would suggest you use other libraries like the standard https or http library that is shipped with node or you can use axios.
If you use a forEach loop without awaiting the results, you'll execute them all at the same time. Moreover, request library is kind of old and you need to convert its functions to return a promise.
Here's how I would do it.
const ssn = [1,2,3,4];
function download(item) {
return new Promise(function(resolve, reject) {
let options = {}; // construct your request
request(options, function (error, response) {
if(error) {
return reject(error);
}
resolve(response);
})
}
}
ssn = ssn.map(async function(item) {
let res = await download(item);
// process the result
return res;
});
You can also use the Bluebird library or get another client library such as got or axios.

(GET) API Request Failed in Javascript

I'm trying to fetch API data from antares (IoT Platform) using native javascript, here's the code
var url = 'https://platform.antares.id:8443/~/antares-cse/antares-id/SuhuPagarsih/Temperature/la';
var opt = {
method: 'GET',
mode: 'no-cors',
headers: {
'X-M2M-Origin': 'bdc2996719c6ac07:8cbb60e9c5997e74',
'Content-Type': 'application/json;ty=4',
'Accept':'application/json',
},
}
fetch(url, opt)
.then(function(data) {
console.log(data)
})
.catch(function(err) {
console.error(err)
})
Here's the result
as you can see, it's failed. Most of the time I see the error reason is forbidden. But when I try using node js and snippet code from postman. I get a good result (200 OK) Here's the code if you need to compare (I guess it's all the same)
var http = require("https");
var options = {
"method": "GET",
"hostname": "platform.antares.id",
"port": "8443",
"path": "/~/antares-cse/antares-id/SuhuPagarsih/Temperature/la",
"headers": {
"x-m2m-origin": "bdc2996719c6ac07:8cbb60e9c5997e74",
"content-type": "application/json;ty=3",
"cache-control": "no-cache",
"postman-token": "ff6cbe83-97ac-6ed5-aaec-e2bafaf44002"
}
};
var req = http.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function () {
var body = Buffer.concat(chunks);
console.log(body.toString());
});
});
req.end();
And here's the result
My questions is, what seems to be the problem? what's the difference between making API request from native javascript and node js? and how can I resolve this problem?
Or maybe is there anyway around this issues? My goal is only to show the data from API to HTML/Web Page
Thank you!

Getting response, body and error from an asynchronous method making a POST API call

I am using this example to make a POST API call to an API: https://nodejs.dev/making-http-requests-with-nodejs#perform-a-post-request. No issues there, it works well.
Next, I wanted to create a function that makes this API call by taking in dynamic connection parameters, headers and payload. Did that and I am able to return the response object from the function so I can detect the response.statusCode, response.statusMessage, etc. Here's my Node.js code:
Module Code
const https = require("https");
function postLendingApplication(connection, data, callback) {
const options = {
hostname: connection.hostname,
port: connection.port,
path: connection.path,
method: connection.method,
headers: connection.headers
};
//console.log(options)
const req = https.request(options, res => {
console.log(`statusCode: ${res.statusCode}`);
res.on("data", d => {
process.stdout.write(d);
});
callback(res);
});
req.on("error", error => {
console.error(error);
});
req.write(data);
req.end();
}
exports.postLendingApplication = postLendingApplication;
Invoking the code from another file
const bpc = require("./public-api");
const data = JSON.stringify({
title: 'foo',
body: 'bar',
userId: 1
});
const connection = {
hostname: 'jsonplaceholder.typicode.com',
port: 443,
path: '/posts',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length,
}
}
var response = bpc.postLendingApplication(connection, data, function(response) {
console.log("Inside the calling function");
//console.log(response);
console.log("Status Code: " + response.statusCode);
console.log("Status Message: " + response.statusMessage);
});
Successful console response
statusCode: 201
Inside the calling function
Status Code: 201
Status Message: Created
{
"title": "foo",
"body": "bar",
"userId": 1,
"id": 101
}
Question: In my callback method, I would like to receive the response body (The JSON) as well as the error so I can run some assertions based on the response/body/error that I received. I am not able to figure out how to setup callback in the module method so it can return all 3 values. If you can please help out with that, it would be greatly appreciated.
Here's the Repl URL in case you'd like to take a stab at it online: https://repl.it/#varun_verma/POST-API
I am not 100% on the question you are asking, I personally if you are wanting to use callbacks in this way use two functions one to handle the error and one for the succsessful response
however, you can use object destruction to give you undefined or default it to null if you like for the item not passed back as shown below:
Module Code
const https = require("https");
function postLendingApplication(connection, data, callback) {
const options = {
hostname: connection.hostname,
port: connection.port,
path: connection.path,
method: connection.method,
headers: connection.headers
};
//console.log(options)
const req = https.request(options, res => {
console.log(`statusCode: ${res.statusCode}`);
let data = ''
res.on("data", d => {
data += d;
});
res.on('end', () => {
callback({response: res, data});
});
});
req.on("error", error => {
console.error(error);
callback({response: res, error});
});
req.write(data);
req.end();
}
exports.postLendingApplication = postLendingApplication;
Invoking the code from another file
const bpc = require("./public-api");
const data = JSON.stringify({
title: 'foo',
body: 'bar',
userId: 1
});
const connection = {
hostname: 'jsonplaceholder.typicode.com',
port: 443,
path: '/posts',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length,
}
}
var response = bpc.postLendingApplication(connection, data, function({ response, data, error}) {
// if error is not passed back in the object it defaults to undefined
if (error) console.error(error)
console.log("Inside the calling function");
//console.log(response);
console.log("Status Code: " + response.statusCode);
console.log("Status Message: " + response.statusMessage);
});
If I understand your question correctly, you want to have the response, data, and the error passed to the callback. (where you currently only pass the response)
You can pass the data to the callback like so:
const req = https.request(options, res => {
console.log(`statusCode: ${res.statusCode}`);
let data = '';
res.on("data", d => {
data += d;
});
res.on('end', () => {
callback(res, data);
});
});
This buffers the data from the response as it comes in into a string and then only when the response ends passes both the response object and the data as a string to the callback. (you can then use JSON.parse in the callback to convert the data string to an object)
Passing the error is more difficult as the error callback is given separately from the response. I would recommend having a separate callback for the error:
function postLendingApplication(connection, data, callback, error_callback) {
...
req.on("error", error => {
console.error(error);
error_callback(error);
});
...
}
However someone else on here may be able to give a better solution for the error.

Save a response Request.post token in variable

I just need to take the token returned in API to complete a URL. I need to take the response.body and save in a variable to use after.
I'm using the protractor to automation tests, and to open a URL I'm consuming an API that return a token, to be used as a parameter in a URL
describe('TEste API', function(){
var Request = require('request');
it("api Testing in protractor", async function (callback) {
let tokenReturn = "empty";
tokenReturn = Request.post({
"headers": { "content-type": "application/x-www-form-urlencoded" },
"url": "https://corpqa.sts.ford.com/adfs/oauth2/token",
"form": {
"grant_type":'client_credentials',
"client_id":'ad9cdf61-e863-4606-a90a-cf7b7141234',
"client_secret":'QmjeT5UZ0N1M0jOEcggrxgFzw-vrZY2UphAy21d5',
"resource":'urn:age:pcf:sss:dev',
}
}, (error, response, body) => {
if (error) {
return console.dir(error);
}
resp = JSON.parse(response.body);
console.log("inside: " + resp.access_token);
callback();
});
console.log("outside: www.example.com/?token=" + tokenReturn);
});
});//------------------------- end describe
In console show me.
outside:
www.example.com/?token=[object Object]
inside:
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IldzZks3Q2FtMDZKY3dkR1Z6a2NiYVUzd21wZyJ9.eyJhdWQiOiJ1cm46YWdlOnBjZjpzdGY6ZGV2IiwiaXNzIjoiaHR0cHM6Ly9jb3JwcWEuc3RzLmZvcmQuY29tL2FkZnMvc2VydmljZXMvdHJ1c3QiLCJpYXQiOjE1NzMyMzIzNjYsImV4cCI6MTU3MzIzNTk2NiwiYXBwdHlwZSI6IkNvbmZpZGVudGlhbCIsImFwcGlkIjoiYWQ5Y2RmNjEtZTg2My00NjA2LWE5MGEtY2Y3YjcxNDE4OTQ1IiwiYXV0aG1ldGhvZCI6Imh0dHA6Ly9zY2hlbWFzLm1pY3Jvc29mdC5jb20vd3MvMjAwOC8wNi9pZGVudGl0eS9hdXRoZW50aWNhdGlvbm1ldGhvZC9wYXNzd29yZCIsImF1dGhfdGltZSI6IjIwMTktMTEtMDhUMTc6MDQ6MjYuMTU5WiIsInZlciI6IjEuMCJ9.kuVfmgvN7_t4h2LB5o6dzTV2hngdapMrWFRPANISg5ayUnqeBMKHI5PWvISddfZ2qjO7kSPXlYVffhjrBhqAxY75EAhLX8hAmHDm_2jl49prtnsnqV-l-zhFaqCyfhEcgtVCRE_GX6EON2pewsX09Vdbn_2uHvh5wcGdWCnontzkZdrf__X8-tuE5R7tHrtge0ZXMdx5bCF7INKzA1YolTwxOOiYNVvZFPDKLRwa4VUf_qTKN5BmLisRVN4gmnTzGTPXjXlHZApRwJAbXR4V7VhtVQ6VcjHuyYIpp_rK0K7kQjwu0FLpE1FHZTNRwvXNI1VqyhGaanx2bM_59NyDgg
I just want the outside result to be equal to the inside with token.
I made some changes but the result change to UNDEFINED instead OBJECT.
Maybe use promises ?
Example:
function requestToServer(){
return new Promise((resovle, reject) => {
Request.post({
"headers": { "content-type": "application/x-www-form-urlencoded" },
"url": "https://corpqa.sts.ford.com/adfs/oauth2/token",
"form": {
"grant_type":'client_credentials',
"client_id":'ad9cdf61-e863-4606-a90a-cf7b7141234',
"client_secret":'QmjeT5UZ0N1M0jOEcggrxgFzw-vrZY2UphAy21d5',
"resource":'urn:age:pcf:sss:dev',
}
}, (error, response, body) => {
if (error) {
return console.dir(error);
}
resp = JSON.parse(response.body);
console.log("inside: " + resp.access_token);
resovle(resp.access_token);
callback();
});
});
}
describe('TEste API', function(){
var Request = require('request');
it("api Testing in protractor", async function (callback) {
let tokenReturn = await requestToServer();
console.log("outside: www.example.com/?token=" + tokenReturn);
});
});//------------------------- end describe

Azure Functions JS: http(s) POST request call inside function not working

I am currently switching from aws lambda to azure functions and try to convert my lambda function (js) to azure function (js). One of the things I need to do in my function is to send a HTTPS Post Request to a URL to get some data. That worked perfectly fine in aws lambda. However, it seems like azure functions is either not supporting this or I am doing something wrong as it never sends the request and just ends the whole function.
This is my code:
var https = require('https');
var http = require('http');
module.exports = async function (context, req) {
var http_options = {
hostname: 'somehostname',
port: 443,
path: 'somepath',
method: 'POST',
headers: {
'Content-Type': 'text/xml;charset=UTF-8',
'SOAPAction': '"https://someURL"'
}
};
var body = '';
context.log('before request');
var req = await https.request(http_options, function (res) {
res.setEncoding('utf8');
body = '';
context.log('inside request');
res.on('data', (chunk) => {
body = body + chunk;
});
context.log('in req 2');
res.on('end', () => {
var options = {
compact: false,
ignoreComment: false,
spaces: 1
};
var result = JSON.parse(body);
})
})
};
The function always prints the "before request" part, and the just terminates.
I also tried a simple http call as described in this SO question. However, same result, the function just ends.
I don't think that https.request() is an async method (doesn't return a promise-like type). What if you try removing your await keyword there?
var https = require('https');
var http = require('http');
module.exports = async function (context, req) {
var http_options = {
hostname: 'somehostname',
port: 443,
path: 'somepath',
method: 'POST',
headers: {
'Content-Type': 'text/xml;charset=UTF-8',
'SOAPAction': '"https://someURL"'
}
};
var body = '';
context.log('before request');
https.request(http_options, function (res) {
res.setEncoding('utf8');
body = '';
context.log('inside request');
res.on('data', (chunk) => {
body = body + chunk;
});
context.log('in req 2');
res.on('end', () => {
var options = {
compact: false,
ignoreComment: false,
spaces: 1
};
var result = JSON.parse(body);
});
});
};

Categories