I've been teaching myself Node.js and Express, and I am trying to return the JSON result from a Google Maps Geocoding API request. I have gotten it to to work using the require module, BUT I am trying to figure out what I did wrong in Express so I have learned it:
Express Attempt: htmlController.js
// FYI: This controller gets called from an app.js file where express() and
// the mapsAPI is passed as arguments.
var urlencodedParser = bodyParser.urlencoded({extended: false});
module.exports = function(app, mapsAPI){
app.post('/maps', urlencodedParser, function(req,results){
var lat;
var long;
var add = req.body.add;
app.get('https://maps.googleapis.com/maps/api/geocode/json?address=' + add + '&key=' + mapsAPI, function(req,res){
lat = res.results.geometry.northeast.lat;
long = res.results.geometry.northeast.long;
console.log(lat); // no output
console.log(lat); // no output
}, function(){
console.log(lat); // no output
console.log(long); // no output
});
results.send("Thanks!");
});
}
As you can see, I am trying to log it in different code blocks, but any log inside the API request is not getting shown to the console.
Working Request using the require Module:
app.post('/maps', urlencodedParser, function(req,results){
var add = req.body.add;
request({
url: 'https://maps.googleapis.com/maps/api/geocode/json?address=' + add + '&key=' + mapsAPI,
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
console.log(body) // Print the json response
}
});
results.send("Thanks!");
});
If I understand you correctly, you are trying to get data from maps api by using app.get()
app.get('https://maps.googleapis.com/maps/api/geocode/json?address=' + add + '&key=' + mapsAPI, function(req,res){}
But app.get() function is used for your app route only, not to fetch remote data. same for router.get()
// app.get(appRoute, middlewareORhandler)
app.get('/myOwnApp/api/users/12/', function(res,res,next)){
// your code here
res.status(200).send("return your response here");
}
to make a remote request you can use built-in httpmodule. request and superagent are great and easy to make remote requests
to install those module:
npm install request --save
var request = require('request');
npm install superagent --save
var request = require('superagent');
see more at : https://www.npmjs.com/package/request
Related
I am new to NodeJS and trying to use npm spotcrime package to get crime data from user input location on click of a button through ajax call. Here is the usage of the package given on npm documentation page of package.
var spotcrime = require('spotcrime');
// somewhere near phoenix, az
var loc = {
lat: 33.39657,
lon: -112.03422
};
var radius = 0.01; // this is miles
spotcrime.getCrimes(loc, radius, function(err, crimes){
});
which works perfectly fine when run separately and returns correct crime json data. However I don't understand how to call this through ajax call on click of button. Any insights would be really helpful. Thanks in advance :)
UPDATE
Here is my server code
var express = require('express');
var app = express();
var dataFile = require('./data/data.json');
var reload = require('reload');
var path = require('path');
app.set('port', process.env.PORT || 3000);
app.set('appData', dataFile);
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');
app.use(express.static(path.join(__dirname, '/public')));
app.use(require('./routes/index'));
app.use(require('./routes/information'));
app.use(require('./routes/spotcrime'));
var server = app.listen(app.get('port'), function(){
console.log('Go to http://localhost:' + app.get('port')+ ' on your
browser');
});
reload(app);
And here is spotcrime.js file
var express = require('express');
var router = express.Router();
var spotcrime = require('spotcrime');
router.get('/spotcrime', function(request, response){
var loc = {
lat: 33.39657,
lon: -112.03422
};
var radius = 0.01; // this is miles
spotcrime.getCrimes(loc, radius, function(err, crimes){
response.send(crimes);
});
});
module.exports = router;
I am trying this from quite a while but nothing shows up. Please suggest any way out
use this code to make ajax call
var http = require('http');
var request = require('request');
request.post({
url: "xxxxxxxxxxxx",
method: "POST",
json: true, // <--Very important!!!
body: {}
},
function(error, response, body) {
if (!error) {
console.log(body.d);
} else {
console.log(error);
}
}
);
If I understood correctly you want to send an AJAX request from a browser(front-end) to your server. This can easily be done with jQuery AJAX see the official documentation page. Here is an example for you:
<buttom class="send-request">Send AJAX request</button>
$(".send-request").click(function() {
$.ajax({
method: "GET", // since you are waiting for GET request on server
url: "/spotcrime", // you might have to provide full path to your endpoint starting with https://127.0.0.1/spotcrime
data: { Greetings: "Hello" } // data object can be deleted since you don't expect any parameters on server side
})
.done(function( msg ) {
alert( "Response data: " + msg );
});
});
I have a situation where in order to get images for a site that I am building, I need to make a http request to an external server for information. Currently, the responses from the requests come in two forms, XML and images. I am doing this using Node.js.
For the XML, I'm able to parse it without issues and it can be passed into a variable and handled like everything else. With the images, I'm stuck, I have no idea how to get them "displayed" on the page after making the request for them. The farthest I have been able to get is to correctly set the request up in postman. My question is, can I pull the image from the body of the response of the request that I'm making to another server and get it to display in the web app that I'm building?
I'm very new to the back end world and am trying to learn as I go. This is an example of what I have been able to do find and use for parsing an XML response that I get from the API
var request = require("request");
var express = require("express");
var jsxml = require("node-jsxml");
var app = express();
var fs = require("fs");
app.get('/users', function(req,res) {
console.log("List of users requested.");
// We will grab the list of users from the specified site, but first we have to grab the site id
// (Same idea as when we added users. We could have checked if req.session.SiteID has been populated,
// but I chose to keep it simple instead)
request(
{
url: 'http://' + SERVERURL + '/api/2.0/sites/' + SITE + '?key=name',
headers: {
'Content-Type': 'text/xml',
'X-Tableau-Auth': req.session.authToken
}
},
function(err, response, body) {
if(err) {
req.session.err = err;
res.redirect('/');
} else {
var bodyXML = new jsxml.XML(body);
console.log("site id: " + siteID);
}
// OK. We have the site, now let's grab the list of users
// Since we're just making a GET request, we don't need to build the xml. All the is needed
// is the SiteID which is inserted in the url and the auth token which is included in the headers
request(
{
url: 'http://' + SERVERURL + '/api/2.0/sites/' + siteID + '/users/',
headers: {
'Content-Type': 'text/xml',
'X-Tableau-Auth': authToken
}
},
function(err, response, body) {
if(err) {
req.session.err = err;
} else {
// A succesful request returns xml with a <users> which contains multiple <user> elements.
// The <user> elements have name attributes and id attributes which we'll grab, store in a
// javascript object and render those in the html that loads.
var bodyXML = new jsxml.XML(body);
bodyXML.descendants('user').each(function(item, index) {
userIDs[item.attribute('name').getValue()] = item.attribute('id').getValue();
});
for(var user in userIDs) {
console.log(user + " " + userIDs[user]);
}
}
res.render("users.ejs", {
err: req.session.err,
userIDs: userIDs,
site: SITE
});
}
);
}
);
});
Any help would be hugely appreciated. Thanks!
Step 1: Fetch image and save it on node server. request module documentation on streaming for more options
request('http://google.com/doodle.png').pipe(fs.createWriteStream('doodle.png'));
Step 2: send the saved image as response.
app.get('/display', function(req, res)) {
fs.readFile('doodle.png', function(err, data) {
if (err) throw err; // Fail if the file can't be read.
else {
res.writeHead(200, {'Content-Type': 'image/jpeg'});
res.end(data); // Send the file data to the browser.
}
});
};
I am looking to get data from steam api. This is what my server.js looks like.
I get the steamID from the req.query thing. Then I want them passed to the function as the last part of the url string.
So far I've tested the following: forced the key directly into the var url and removed the function. It worked.
I tried to create a var rekt after the req.query, and passed it like getData(rekt). It didn't work.
So I think calling of the function doesn't work because there is a different syntax for this in node js(as I'm new in it.) Hopefully it's enough information.
var request = require('request');
var express = require('express');
var app = express();
var gotSteamID;
app.use(express.static('site'));
app.get('/data.html', function(req, res){
gotSteamID = req.query.SteamID;
getData(gotSteamID);
});
function getData(gotSteamID) {
app.get('/steam/stats', function(httpRequest, httpResponse) {
var url = 'http://api.steampowered.com/ISteamUserStats/GetUserStatsForGame/v0002/?appid=730&key=IREMOVEDTHEKEY&steamid=' + gotSteamID;
request.get(url, function(error, steamHttpResponse, steamHttpBody) {
httpResponse.setHeader('Content-Type', 'application/json');
httpResponse.send(steamHttpBody);
});
});
}
var port = 4000;
var server = app.listen(port);
and the html post looks like
<form class="form" action="data.html" method="GET">
<input type="text" name="SteamID" placeholder="76561198101455802" id="steamIDvalue" name="selectpicker" required>
<input type="submit" name="submit" value="➜" onclick="getValue()" id="rekt">
</form>
Instead of the 2 app.get (one inside the function), why don't you expose 1 API call that gets the ID in the parameter?
app.get('/steam/stats/:id', function(httpRequest, httpResponse) {
var url = 'http://api.steampowered.com/ISteamUserStats/GetUserStatsForGame/v0002/?appid=730&key=IREMOVEDTHEKEY&steamid=' + id;
request.get(url, function(error, steamHttpResponse, steamHttpBody) {
httpResponse.json(steamHttpBody);
});
});
Then in the html, you need to call /steam/stats/id instead of /data.html?SteamId=xxx
Ultimately, it looks like you're attempting to setup another endpoint (via app.get()) in your request handler for /data.html. With that removed, your request.get() will now be invoked.
Using query params
The following should allow you to make GET requests to /data. I removed the .html since you're actually serving JSON from this endpoint (you'll want to change this in your form)
var request = require('request');
var express = require('express');
var app = express();
app.use(express.static('site'));
var appid = 730;
var key = 'IREMOVEDTHEKEY';
var api = 'http://api.steampowered.com/ISteamUserStats/GetUserStatsForGame/v0002/';
app.get('/data', function(req, res){
var steamId = req.query.SteamID;
var url = api + '?appid='+ appid +'&key='+ key +'&steamid=' + steamId;
request.get(url, function(error, response, body) {
res.setHeader('Content-Type', 'application/json');
res.send(body);
});
});
app.listen(4000);
Using URL params
If you'd like to move away from using a query param, you could use something like the following:
app.get('/steam/stats/:steamId', function(req, res){
var steamId = req.params.steamId;
var url = api + '?appid='+ appid +'&key='+ key +'&steamid=' + steamId;
request.get(url, function(error, response, body) {
res.setHeader('Content-Type', 'application/json');
res.send(body);
});
});
Cleaning up your Request
String concatenation is nice, but request offers a more convenient (and easier to read/maintain) way to create your API URL.
qs - object containing querystring values to be appended to the uri
If you broke out your appid and key as I did above, you can pass them to qs without having to worry about ? and & URL management.
request.get({
url: api,
qs: {
appid: appid,
key: key,
steamid: req.params.steamId
}
});
Just a friendly tidbit to help tidy up your code and save you from some potential frustration down the road.
I have an endpoint defined at /api/profile which accepts post parameters.
var http = require('http');
var serverConfig = require('../server.config.js');
var request = require('request');
module.exports = function(server){
server.route({
method: 'POST',
path: '/api/profile',
handler: getProfileData
});
function getProfileData(request, reply){
var battleTag = request.payload.battleTag;
getProfileDataHttp(battleTag, function(err, data){
if(err){
reply(new Error(err));
}
reply(data);
});
}
function getProfileDataHttp(battleTag, callback){
var key = serverConfig.battleNet.apiKey;
var tag = encodeURIComponent(battleTag);
var url = 'https://eu.api.battle.net/d3/profile/'+ tag + '/?locale=en_GB&callback=JSON_CALLBACK&apikey=' + key;
console.log(url);
request(url,function(error, response, body){
if(error){
callback(err);
}
if(!error && response.statusCode ==200){
callback(null, body);
}
});
}
};
it is calling an api with a json callback, when I am receiving the data it is in format:
JSON_CALLBACK({ json data here})
how can I get this endpoint to return just the json data, I have tried JSON.parse() but it causes errors in the server.
the angular service that calls this endpoint is like below:
function getProfileData(battleTag){
var defer = $q.defer();
var tag = validTag(battleTag);
if(!tag){
defer.reject('Invalid Tag please use format 1[a-z]11[a-z0-9]#4[0-9]');
return defer.promise;
}
$http.post('/api/profile', {
battleTag: battleTag
})
.success(function(data){
if(data.reason){
defer.resolve(data.reason);
}
defer.resolve(data);
})
.error(function(err){
defer.reject(err);
});
return defer.promise;
}
the call would work when using $http.jsonp in angular however I had to create the server to hide the secret key from the client
Your question is a bit confusing. You are talking about JSONP, but you want to fetch the data directly.
The whole point of JSONP is to return the data encapsulated inside a function that you choose. You then simply have to execute it.
If you want the data in a direct way, don't use JSONP. Simply do a "normal" call.
After having a quick look at the Battle.net API, it seems that to get the data directly, you should simply omit the 'callback' parameter in the URL of your request.
Thus, your request URL would looks like that:
var url = 'https://eu.api.battle.net/d3/profile/'+ tag + '/?locale=en_GB&apikey=' + key;
I am trying to interface with an external API and I need to POST an XML document over HTTPS.
So I am using the node https interface to try to make the request but if I try to write any data (The XML document) it throws a socket hang up. If I write nothing or an empty string to the request it completes the post just fine.
I've googled and found other people with this error but I haven't been able to fix it following the solutions others have found.
I am using Meteor, which has the HTTP package for making these types of requests. The HTTP package was also throwing this error so I dug down and implemented the post using the node 'https' package thinking it would solve the issue but I get the same error with https as well.
Here is my code:
var http = Npm.require("http");
var oauthSignature = Npm.require('oauth-signature');
var URL = Npm.require('url');
var content = "XML String Here";
var postDestinationUrl = "https://example.com/api/path";
var authObject = {
oauth_consumer_key: "consumerKey",
oauth_signature_method: "HMAC-SHA1",
oauth_timestamp: (Math.round(new Date().getTime() / 1000)).toString(10),
oauth_nonce: Random.id(),
oauth_version: "1.0"
};
authObject.oauth_signature = oauthSignature.generate("POST", postDestinationUrl, authObject, "shared Secret Here");
var authString = objectToQueryString(authObject);
var headers = {
Connection: "keep-alive",
'Content-Length': Buffer.byteLength(content),
Authorization: authString,
'Content-Type': 'application/xml'
};
var parsedUrl = URL.parse(postDestinationUrl);
var requestOptions = {
hostname: parsedUrl.hostname,
path: parsedUrl.pathname,
method: "POST",
headers: headers
};
var request = https.request(requestOptions, function(response){
var body = '';
console.log("statusCode from https.request: ", response.statusCode);
console.log("headers from https.request: ", response.headers);
response.on("data", function(data){
body += data;
}); // end of data
response.on("end", function(){
console.log("body from https.request: ", body);
}); // end of end
response.on("error", function(){
console.log("error in https.request response");
}); // end of error
}); // end of request
request.write(content);
request.end();
request.on("error",function(error){
console.log("Error in https.request: " + error.message);
callback(error, undefined);
}); // end of error
var objectToQueryString = function(queryObject){
var queryString = "";
_.each(queryObject, function(value, key, list){
queryString += key + '="' + value +'",';
});
return queryString.substr(0, queryString.length -1);
};
And the error I am seeing:
"stack":"Error: socket hang up
at Object.Future.wait (/Users/dsyko/.meteor/tools/f3947a4651/lib/node_modules/fibers/future.js:326:15)
at packages/meteor/helpers.js:111
at Meteor.methods.submitAPIPost (packages/api-interface/api_server.js:412)
at packages/check/match.js:77
at _.extend.withValue (packages/meteor/dynamics_nodejs.js:35)
at Object.Match._failIfArgumentsAreNotAllChecked (packages/check/match.js:76)
at maybeAuditArgumentChecks (packages/livedata/livedata_server.js:1403)
at packages/livedata/livedata_server.js:580
at _.extend.withValue (packages/meteor/dynamics_nodejs.js:35)
at packages/livedata/livedata_server.js:579
- - - - -
at createHangUpError (http.js:1472:15)
at CleartextStream.socketCloseListener (http.js:1522:23)
at CleartextStream.EventEmitter.emit (events.js:117:20)
at tls.js:696:10
at process._tickCallback (node.js:415:13)"
I've used postman to make the same API request and it goes through just fine so it doesn't seem to be a bad endpoint. I also switched over to posting to http and used Wireshark to inspect the headers and content of the HTTP POSTs to make sure I'm not mangling something in the request but it all looked ok there. Also when I switched over to http the XML document goes through just fine and I don't see the socket hangup (Although the endpoint responds with a re-direct to the https url so I can't just use http)