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

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 🙏.

Related

Response doesn't wait for async function

I found the aproach how to put the async function into a router endpoint and tried to implement it but not suceed. E.g. this link zellwk.com
The server sends only empty string instead of a huge string that is on snippet.host.
async function downloadData(url) {
const options = {
'method': 'GET', 'url': url, 'headers': {}, formData: {}
};
let result = '';
await request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body)
result = response.body
});
return {error: 0, text: result}
}
app.get('/token/:token', jsonParser, async function (req, res) {
console.log(req.params.token) //Don't mind this token
try {
let message = await downloadData('https://snippet.host/xgsh/raw')
res.send(message)
} catch (e) {
console.log(e);
res.sendStatus(500);
}
});
How to make it wait for the download?
EDIT
I implemented node-fetch and got this:
{"error":0,"text":{"size":0}}
What did I wrong?
async function downloadData(url) {
const result = await fetch(url)
return {error: 0, text: result}
}
app.get('/token/:token', jsonParser, async function (req, res) {
console.log(req.params.token)
try {
let message = await downloadData('https://snippet.host/xgsh/raw')
res.send(message)
} catch (e) {
console.log(e);
res.sendStatus(500);
}
});
in case of fetch call the response body need to be parsed first which you are missing.
async function downloadData(url) {
const res = await fetch(url)
if (res && res.status != 200)
throw new Error("status code other than 200 received")
let json = await res.json()
return {error: 0, text: json}
}
app.get('/token/:token', async function (req, res) {
console.log(req.params.token)
try {
let message = await downloadData('https://snippet.host/xgsh/raw')
// let json = await message.json()
res.send(message)
} catch (e) {
console.log(e);
res.sendStatus(500);
}
});
i tried calling the api but every time it is returning 404 . so json cant be called in that case. but if 200 is returned then you call json and return that accordingly.
You can only usefully await a promise.
request doesn't return a promise, it takes a callback function instead.
This is one of the reasons that request was deprecated two years ago.
Replace request with something which supports promises such as node-fetch, the native fetch that was added to Node.js recently, or axios.
In case you must use request (eventhough it's deprecated); or in case you find a similar situation with a old function that doesn't return a promise; you can turn your request into a function that returns a promise.
Either write your own wrapper, in the form of
function requestPromise(options) {
return new Promise(
(resolve,reject) => request(options,
(err,response) => if (err) reject(err) else resolve(response)));
}
or, given that request's callback is in the form of function(err,response), directly use util.promisify
async function xxxx(...) {
try {
...
let response = await util.promisify(request)(options);
...
}
Because request isn't actually an async function that returns a Promise, you can create your own async version of request.
function asyncRequest(options) {
return new Promise((resolve, reject) => {
request(options, (err, response) => {
if (err) {
reject(err)
} else {
resolve(response)
}
})
})
}
Then in your project rewrite your downloadData function to be:
async function downloadData(url) {
const options = {
method: "GET",
url: url,
headers: {},
formData: {},
}
const result = await asyncRequest(options)
return { error: 0, text: result.body }
}

how to get data outside request

I have a scenario where i need to take response (body) of request method outside request. How can i do it?
request.post({
url: 'http://localhost/api/messages',
form: { key: message }
}, function (err, httpResponse, body) {
tmsg = body;
})
console.log(tmsg);
I need this tmsg outside for next processing, Actual scenario is as below.
app.post('/incomemsg', function (req, res) {
var mediaCount = req.body.NumMedia;
if (mediaCount == 0) {
//var twiml = getResponse(message);
var twiml = new MessagingResponse();
request.post({
url: 'http://localhost:3978/api/messages',
form: { key: message }
}, function (err, httpResponse, body) {
tmsg = body;
})
console.log(tmsg);
}else {
//dosomething which outputs tmsg
}
res.writeHead(200, { 'Content-Type': 'text/xml' });
res.end(tmsg.toString());
});
The problem is you are trying to assign value to a global variable in request.post's callback() which is only called after request.post is executed by Asynchronous logic(API calls are all async), so a better way would be to promisify request.post and await the request.post to make it seem synchronous.
const requestPromisified = requestObject =>
new Promise((resolve, reject) => {
request.post(requestObject, function(err, httpResponse, body) {
if (err) {
reject(err);
}
resolve(body);
});
});
const body = await requestPromisified({
method: "POST",
url: "http://localhost/api/messages",
form: { key: message }
});
You only can do something with tmsg when you made the request so you need to rearrange your code like this:
app.post('/incomemsg', function (req, res) {
var mediaCount = req.body.NumMedia;
var twiml = new MessagingResponse();
request.post({
url: 'http://localhost:3978/api/messages',
form: { key: message }
}, function (err, httpResponse, body) {
tmsg = body;
console.log(tmsg);
if (mediaCount === 0) {
//do something with tmsg
} else {
//do something else with tmsg
}
res.writeHead(200, { 'Content-Type': 'text/xml' });
res.end(tmsg.toString());
});
});
Otherwise tmsg will be null because there was no request made to fill that variable.

how to make async/await work properly in node js?

i am new to node js coding i have two functions in my code one of them,i have made async using async keyword but the issue is it doesn't work the output from second function comes before the first function but i want the output of first function before the second function below given is my code
var request = require("request").defaults({jar: true});
var cookieJar = request.jar();
var options = { method: 'POST',
url: 'http://69.30.210.130:8082/api/session',
headers:
{ 'content-type': 'application/x-www-form-urlencoded' },
form: { email: 'admin', password: 'admin' } };
request(options, async function (error, response, body) {
if (error) throw new Error(error);
let bod=await body;
console.log(bod)
});
var options = { method: 'GET',
url: 'http://69.30.210.130:8082/api/devices',
qs: { id: '1' },
headers:
{ 'postman-token': '021a3566-e1ea-4dd4-4ceb-c81ecd25ddd1',
'cache-control': 'no-cache' } };
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
request uses callbacks as default, it means when you want to chain multiple request, you have to do in this manner:
// first request
request({...}, function(error, response, body1) {
if (error) return console.error('Error', error.message);
// second request
request({...}, function(error, response, body2) {
if (error) return console.error('Error', error.message);
console.log(body1, body2);
});
});
async/await is meant to simplify working with promises, so you can use request-promise:
const rp = require('request-promise');
(async function() { // await can be called only from within an async func
try {
const body1 = await rp({...}); // first request
const body2 = await rp({...}); // second request
console.log(body1, body2);
} catch (e) {
console.error('Error', e.message);
}
})();
Here, the body2 will be resolved after body1 has been resolved. This means async/await brings a synchronous behavior into the asynchronous processing.
You can use axios which is Promises-base out of the box.
EDIT: async from callbacks removed, axios reference added

How to migrate to callback nodejs

I need to transform this code into clean code that uses callbacks, because this code does not allow me to use body information elsewhere.
const endpoints = [];
function getDevicesFromPartnerCloud() {
var options = {
method: 'GET',
url: 'https://database-dcda.restdb.io/rest/endpoints',
headers: {
'cache-control': 'no-cache',
'x-apikey': '*****************************'
}
};
request(options, function (error, response, body) {
var data = JSON.parse(body);
data.forEach(function(data, index) {
let endpoint = createSceneEndpoint(data._id, data.name);
endpoints.push(endpoint);
});
});
return endpoints;
}
I think the cleanest way to do it would be to use a Promise to handle the asynchronous request. One of the most important things to remember is that functions should ideally do only one thing. That way, they are easier to test, reason about, and refactor. I would pull the code that actually makes the request into a separate function and have it return the body, then have your getDevicesFromPartnerCloud call that new function, get the data back, and process it however it wants. Most importantly, this "frees" the data from being stuck in the request callback, because you're wrapping it in a promise, and resolving it when the data is available.
Something like:
const endpoints = [];
function requestDevices() {
return new Promise(function(resolve, reject) {
const options = {
method: 'GET',
url: 'https://database-dcda.restdb.io/rest/endpoints',
headers: {
'cache-control': 'no-cache',
'x-apikey': '*****************************',
},
};
request(options, function(error, response, body) {
if (error) {
reject(error)
}
resolve({ response: response, body: body });
});
});
}
async function getDevicesFromPartnerCloud() {
const devicesResponse = await requestDevices();
const data = JSON.parse(devicesResponse.body);
data.forEach(function(data, index) {
const endpoint = createSceneEndpoint(data._id, data.name);
endpoints.push(endpoint);
});
// Do whatever else you need with devicesResponse.body
return endpoints;
}
If you wanted to go more of an es6 direction, maybe something like
let endpoints;
const requestDevices = () =>
new Promise((resolve, reject) => {
request(
{
method: 'GET',
url: 'https://database-dcda.restdb.io/rest/endpoints',
headers: {
'cache-control': 'no-cache',
'x-apikey': '*****************************',
},
},
(error, response, body) => (error ? reject(error) : resolve(body)),
);
});
const getDevicesFromPartnerCloud = async () => {
try {
const body = await requestDevices();
const data = JSON.parse(body);
endpoints = data.map(({ _id, name }) =>
createSceneEndpoint(_id, name),
);
// Do whatever else you need with devicesResponse.body
// doStuff(body)
return endpoints;
} catch (e) {
console.error(e);
}
};

Node JS Express Call Multiple APIs and return a Single Response

I am extremely new to Node, I hope someone can help.
I have 2 APIs that are external to my project.
I want to create a single endpoint in my Node Express server that returns the results from both calls.
How would I do this?
So far I figured out how to call an external resource like this,
app.use('/myapi', function(req, res) {
var url = 'https://some-service.com/api1';
res.setHeader('content-type', 'application/json');
req.pipe(request(url)).pipe(res);
});
This will return the results to my application. What I cant figure out is how to make a second call, then combine the results into an object like this,
{ response1, response2 }
Does anyone know how to do this, or point me in the right direction?
Also is there a way to make sure that both calls succeed before sending a response to my application.
Thanks.
You have to use promise a functionality like this, as the external calls can take their own sweet time. You can wait for the calls to get complete and send the final response.
You can update your route to something like below :
app.use('/myapi', function(req, res) {
var url = 'https://some-service.com/api1';
res.setHeader('content-type', 'application/json');
var responseOne = await CallFirstSystem();
var responseTwo = await CallSecondSystem();
var finalResponse = doSomeLogic(responseOne,responseTwo);
res.send(finalResponse);
});
Create separate functions to call and handle the response
function CallFirstSystem() {
return new Promise(async function (resolve, reject) {
try {
var url = "http://firssytem/api";
var updateResult = [];
await axios.get(url, JSON.stringify(requestPayLoad), {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
}).then(function (response) {
updateResult = innerLogicOne(response);
})
.catch(function (error) {
console.log(error);
});
resolve(updateResult);
} catch (err) {
console.log(err)
} finally {}
}).catch((err) => {
console.log(err)
});
}
function CallSecondSystem() {
return new Promise(async function (resolve, reject) {
try {
var url = "http://secondSystem/api";
var updateResult = [];
await axios.get(url, JSON.stringify(requestPayLoad), {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
}).then(function (response) {
updateResult = innerLogicOne(response);
})
.catch(function (error) {
console.log(error);
});
resolve(updateResult);
} catch (err) {
console.log(err)
} finally {}
}).catch((err) => {
console.log(err)
});
}
I am using axios to call API, you are free to use any other library to call the external system API.
Hope this helps.

Resources