Handling asynchronous responses in node on server side - javascript

I am trying to build a simple node service that
Handles a GET request from a web client
Parses the params submitted
Uses those params to query another REST service asynchronously
Returns the REST service results back to the original GET request.
I'm just getting started with asynchronous programming in node, in general I'm struggling to understand how to preserve scope between asynchronous calls.
Basically - how do I send the JSON service 'result' back to the original GET request via the 'req'?
I'm using Express and Request, the route handler looks like:
exports.list = function(req, res){
var params = req.query;
var queryParam= params.queryParm;
var restURL = "http://some-json-service.com?queryParam=" + queryParam;
var request = require('request');
request(restURL, function (error, response, body) {
if (!error && response.statusCode == 200) {
var result = JSON.parse(body);
// ? How do I send result back to the req?
}
})

You can literally return the response, so where you have your comment you will do:
request(restURL, function (error, response, body) {
if (!error && response.statusCode == 200) {
var result = JSON.parse(body);
res(result)
}
})
the problem with this approach is that your client request will be pending a response from the second service which is fine if it has to be done. Just be aware of the delay that you might be causing.
Also make sure in case of an error you also return a response.
This seems simple enough, so let me know if I didn't fully understand your question.
Cheers.
Vitor.

Related

Use http.get Node.js with callback

I am trying to implement this library here, which generates QR codes and all other kinds of codes.
The problem I have is making a request where I have access to both req and res object, since I will need to pass these to the library. In the documentation, they are recommending
http.createServer(function(req, res) {
// If the url does not begin /?bcid= then 404. Otherwise, we end up
// returning 400 on requests like favicon.ico.
if (req.url.indexOf('/?bcid=') != 0) {
res.writeHead(404, { 'Content-Type':'text/plain' });
res.end('BWIPJS: Unknown request format.', 'utf8');
} else {
bwipjs.request(req, res); // Executes asynchronously
}
}).listen(3030);
The problem is I already have a server created, and I simply want to call the library in a get request, without creating another server. I have tried
http.get('http://localhost:3030/?bcid=azteccode&text=thisisthetext&format=full&scale=2', (req, res) => {
bwipjs.request(req, res); // Executes asynchronously
}
)
which obviously didn't work as the callback only takes response as an argument.
I would like to use bare node in the implementation as this is the way my server is implemented, and I don't want to add a library (like Express) just for this scenario.
You are heavily misunderstanding the role of http.get
http.get is used to do HTTP GET call to that certain url. It's basically what axios or request or ajax or xhr or postman or browser does.
The url param of http.get is not route. It's literally is the url you want to hit.
If you want to handle specific route you have to do it in the http.createServer() handler itself.
Like,
http.createServer(function(req, res) {
if (req.url.indexOf('/?bcid=') != 0) {
//do something
} else if (req.method == "get" && req.url.indexOf('/?bcid=') != 0){
bwipjs.request(req, res); // Executes asynchronously
} else {
//do something else
}
}).listen(3030);
Check out the req or http.IncomingMessage for available properties that you can use.

How to call web service from Alexa Lambda function

I want to make a GET request to a web site using the Amazon Profile API. I am trying to do what is described in the last code chunk in this article: https://developer.amazon.com/blogs/post/Tx3CX1ETRZZ2NPC/Alexa-Account-Linking-5-Steps-to-Seamlessly-Link-Your-Alexa-Skill-with-Login-wit (very end of article) and it just does not happen. My callback function never seems to get called.
I have added the required context.succeed(), actually the latest version of that, and am still not getting results. I know the url is good, as I can take it and copy/paste into a browser and it returns an expected result.
Here is a SO answer on using the appropriate context function calls within the callback, which I have tried. Why is this HTTP request not working on AWS Lambda?
I am not using a VPC.
What am I doing wrong? I feel like a moron, as I have been researching this and trying solutions for 2 days. I log the full URL, and when I copy/paste that out of the log file, and put it in a browser window, I do get a valid result. Thanks for your help.
Here is the code:
function getUserProfileInfo(token, context) {
console.log("IN getUserProfileInfo");
var request = require('request');
var amznProfileURL = 'https://api.amazon.com/user/profile?access_token=';
amznProfileURL += token;
console.log("calling it");
console.log(amznProfileURL);
console.log("called it");
request(amznProfileURL, function(error, response, body) {
if (!error && response.statusCode == 200) {
var profile = JSON.parse(body);
console.log("IN getUserProfileInfo success");
console.log(profile);
context.callbackWaitsForEmptyEventLoop = false;
callback(null, 'Success message');
} else {
console.log("in getUserProfileInfo fail");
console.log(error);
context.callbackWaitsForEmptyEventLoop = false;
callback('Fail object', 'Failed result');
}
});
console.log("OUT getUserProfileInfo");
}
This is the logging output I get in CloudWatch:
2017-03-08T22:20:53.671Z 7e393297-044d-11e7-9422-39f5f7f812f6 IN getUserProfileInfo
2017-03-08T22:20:53.728Z 7e393297-044d-11e7-9422-39f5f7f812f6 OUT getUserProfileInfo
Problem might be that you are using var request = require('request'); which is external dependency and will require you to make a packaged lambda deployment for it to work. See this answer for relevant information.
AWS Node JS with Request
Another way is that you can use NodeJS module such as var http= require('http'); which is builtin module to make the requests. This way you can just make plain lambda script deployment.
Reference
http://docs.aws.amazon.com/lambda/latest/dg/nodejs-create-deployment-pkg.html

Refresh api query with Node.JS & Heroku

I'm building a messenger bot that queries an API once a day and sends the information contained there to users. it's hosted on Heroku and uses Node.js
I'm currently using this to query the API:
var request = require('request');
//url for classes JSON
var url = 'https://example.api';
//get JSON, parse it and store it in jsonstorage variable
request(url, (error, response, body)=> {
if (!error && response.statusCode === 200) {
jsonstorage = JSON.parse(body)
console.log("Got a response")
} else {
console.log("Got an error: ", error, ", status code: ", response.statusCode)
}
})
The problem with this is that it doesn't refresh the API query ever, so the values returned are always the same. If I try and put it within the functions that send the data once a day though, it claims the jsonstorage variable is 'undefined'.
How can I refresh the query regularly?
Thanks!
Found an answer to this myself - the issue I was running into was that request is asynchronous, so I needed to wait for request to receive a result before running the rest of the script.

what is wrong with this Instagram API call?

What is wrong with this code? I want to pull my hair out! I'm getting JSON from the Instagram API. console logging just body gives me the JSON, but when I do something like body.data or body.pagination, I get nothing! Help please and thank you.
var express = require("express"),
app = express(),
https = require("https"),
fs = require("fs"),
request = require("request");
request("https://api.instagram.com/v1/tags/nofilter/media/recent?access_token=xxxxx&scope=public_content&count=1", function(error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body) // returns all the relevant JSON
console.log(body.data) // **returns undefined!!!!!**
}
}).pipe(fs.createWriteStream("./test.txt"))
body is literally what it says on the tin - the body of the HTTP response. In other words, it's a string - you need to run it through JSON.parse to actually access it as an object.
console.log(JSON.parse(body).data);
Obviously, if you were going to use this for real, you'd assign the parsed object to a variable rather than running it every time you access it.

Google Token Authentication with node.js and express.js

I have a node.js/express webservice that I would like to use to verify Google token coming from a mobile app.
From this tutorial (https://developers.google.com/identity/sign-in/android/backend-auth) I learned that I have to make such a call:
https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=XYZ123
So I came up with this in my code:
var request = require('request');
module.exports = function(app) {
app.get('/authenticate', function(req, res) {
request('https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=XYZ123', function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body)
}
})
});
};
Then, based on the response from google api, I would like to return true or false.
But it doesn't work. When I put "https://www.google.com" in the request, body is printed in the console, but the request is still being executed for some time.
What am I missing here? Is is the correct approach to the problem I described or should I do it in a completely different way?
You need to send a response to your incoming HTTP request.
Call res.send(...).
For more information, see the Express documentation.

Categories

Resources