How to properly do a server side api request? - javascript

I am very new with node js and decided to learn how to secure api keys, i've looked everywhere but can't find a example. But i found some that suggest the only way is to do a server side api request.
I am using openweathermap api for this code, i get the expected data back as a response in chrome network tab but i have questions regarding it.
How do i use the response data (e.g getting the current weather, temp) ?
Is this the proper way on doing a server side api request in node.js?
http.createServer(function(req, res) {
if (req.url === '/') {
res.writeHead(200, {"Content-Type": "text/html"});
fs.createReadStream(__dirname + '/index.html').pipe(res);
} else if (req.url === '/getweather') {
var weatherApiURL = 'https://api.openweathermap.org/data/2.5/weather?q=London,uk&appid=<API KEY>';
request(weatherApiURL, function (error, response, body) {
if (error) {
res.writeHead(500, 'Weather API request failed', {'content-type': 'text/plain'});
res.end();
} else {
res.writeHead(200, {'content-type': 'application/json'});
res.end(body);
}
});
} else {
res.end('not found')
}
}).listen(8080);
Front:
function requestWeatherData() {
var xhr = new XMLHttpRequest();
xhr.open('GET', '/getweather', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function () {
console.log(this.responseText);
};
xhr.send();
};
Thank you in advanced!!

Part 1: How to use the data.
The first thing you'll want to do is to check whether the request succeeded
if (this.status !== 200) {
// The request did not work.
throw new Error('Cannot use data.');
}
Once the requset status has been verified you need to 'parse' the response.
const weatherData = JSON.parse(this.responseText);
// Lets see the js object:
console.log(weatherData);
Now you can do whatever you need with the data.
The full example:
function requestWeatherData() {
var xhr = new XMLHttpRequest();
xhr.open('GET', '/getweather', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function () {
if (this.status !== 200) {
// The request did not work.
throw new Error('Cannot use data.');
}
const weatherData = JSON.parse(this.responseText);
// Lets see the js object:
console.log(weatherData);
};
xhr.send();
};
Part 2: Is there a proper way of doing this?
Now, I don't not know enough about this to say definitely, however, here are some concerns that you may want to think about.
Most APIs have rate limits, meaning you probably want to try to 'cache' the requests somewhere to reduce the need to 'poll' the APIs
Other people could use your exposed url in their application.
Writing all of the routes as you are currently will become a real headache for larger applications, I can recommend express from experience for small to medium applications.

Related

XMLHttpRequest get request response is empty, even with callback

I'm attempting to get a response from a Node application I created using the XMLHttpRequest object in JavaScript. The code I am using to do such is below:
var get = function()
{
var http = new XMLHttpRequest({mozSystem: true});
http.onreadystatechange = function() {
if (http.status === 200) {
console.log(http.responseText);
}
}
http.open("GET", "http://127.0.0.1:3000", true);
http.setRequestHeader("Content-Type", "text/plain");
http.send();
}
And the Node application is:
const http = require('http');
const fs = require('fs');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) =>
{
let body = [];
req.on('data', (chunk) =>
{
body.push(chunk);
}).on('end', () =>
{
body = Buffer.concat(body).toString();
if(req.method === "GET")
{
console.log("GET");
}
res.setHeader('Content-Type', 'text/plain');
res.end("Hello World");
})
});
However, nothing is being printed. I opened the developer tools in Chrome and Mozilla and can see that the status is 200, and the response is listed under the response for the Ajax call - it says clearly "Hello World".
I'm doing this all locally, as a Node demo for school. I have the application able to handle post requests perfectly fine - but getting the response from the GET request does not seem to work. I'm open to any and all advice!
Thank you in advanced.
To answer my question, I was not aware that not having CORs enabled would cause such behavior - the browser would show that the request was going through, the response could be seen in developer tools, but could not be printed to console. Thank you to Jaromanda for helping me come to realize this.

Node.js Doesn't Recognize Ajax Request

I am trying to make a private page dedicated to an Ajax request. Here is the simple request.
window.onload = loaded;
function loaded(){
var xhr = new XMLHttpRequest();
xhr.open('GET', '/data_annotations', true);
xhr.onload = function(){
if(this.status == 200){
var data = xhr.responseText;
console.log(JSON.parse(data));
} else {
console.log("Rip");
}
}
xhr.send();
//httpreq.abort();
}
Here is the node.js that it's running off of:
...
app.get('/', function(req, res, next){
console.log("Connected Successfully.");
res.render('home');
});
app.get('/data_annotations', function(req, res, next){
if(req.xhr || req.headers.accept.indexOf('json') > -1) {
const mc = mongo.MongoClient;
const url = 'mongodb://localhost:27017/';
const dbName = 'practiceMDB';
console.log("Got Data Annotations.");
mc.connect(url, { useNewUrlParser: true }, (err, client) =>{
if(err){
console.log(err);
} else {
const db = client.db(dbName);
data = db.collection('DataAnnotations');
data.find({}).toArray(function(err, data){
res.send(data)
});
client.close();
}
});
} else {
res.redirect('/');
}
});
app.listen(port, function(){
console.log('Server Started on Port '+port);
});
I only want /data_annotaion to run if it's from the Ajax request. If a user types in /data_annotations in the url, it should redirect them to the home page. When I ran this I got these results:
Server Started on Port 3000
Connected Successfully.
Connected Successfully.
This is indicating (to me) that the ajax request isn't registering as an ajax request, and is registering as a normal request. Further, I am getting this error:
Uncaught SyntaxError: Unexpected token < in JSON at position 0
I believe it is due to the redirection. The Ajax request gets redirected, it takes the response of the home page and is unable to parse it (I believe this to be happening because it cannot parse HTML text or string text - don't quote me on that). How do I get Node JS to register my Ajax request?
PS: I looked at this answer to determine if a request is Ajax or not, but it always determines my requests as not Ajax: https://stackoverflow.com/a/28540611/6804700
First thing - In your client-side code you need to set the accept header, because that is what you are looking for in your server side code.
xhr.setRequestHeader("accept", "application/json");
Second you can use the following code to return the data as json in your server side code
res.json(data);
Another comment. It is bad practice to change the result type or redirect in an API. Your url is either returning JSON or redirecting to and HTML page which means the result is not consistent.

Client side can not take the json data

I have a nodejs server and the code that I have as below. I send an AJAX request and I want the server to send me a response of a json data. When I put res.write()("string data like hello hello") in the server code, client side can take the value of inside and I can see the value on the console. But I cannot get json value with this function. I tried res.end() and res.send() functions as well but it didn't work. How can I send the json value and the following client side code can take the value correctly?
Server side,
app.use('/', function(req, res) {
console.log("req body app use", req.body);
var str= req.path;
if(str.localeCompare(controlPathDatabaseLoad) == 0)
{
console.log("controlPathDatabaseLoad");
mongoDbHandleLoad(req, res);
res.writeHead('Content-Type', 'application/json');
res.write("Everything all right with database loading"); //I can get this message
//res.end(json) I can not get json message with this function as well
res.send("OK");
//res.send(JSON.stringify(responseBody)); I can not get json message
}
Client side,
function loadDatabaseData()
{
console.log("loadDatabaseData");
var oReq = new XMLHttpRequest();
oReq.open("GET", "http://192.168.80.143:2800/load", true);
oReq.setRequestHeader("Content-type", "application/json;charset=UTF-8");
oReq.onreadystatechange = function() {//Call a function when the state changes.
if(oReq.readyState == 4 && oReq.status == 200) {
console.log("http response", oReq.response);
console.log("http responseText", oReq.responseText);
}
}
oReq.send();
}

Make http call from within Javascript Express app

I am building an express (http://expressjs.com/) app which will create an API by parsing another webpage. Here is how I create my route:
app.get('/api/json', test.jsonParser);
Here is my jsonParser method:
exports.jsonParser = function(req, res) {
var client = new XMLHttpRequest();
client.open('GET', smhiURL);
client.onreadystatechange = function() {
if (client.readyState == 4 && client.status == 200) {
if (client.responseText) {
res.render('hello', { message: 'Congrats, you just set up your app!' });
} else {
res.status(404).send("Page not found.");
}
}
}
client.send();
}
Them messag I am sending in the onreadystatechangeis just using defult template so I can test if everything is ok but its not, I am getting NetworkError: 500 Internal Server Error
Any ideas why this is not working? I am guessing there is some async problems but, and the rendermethod is called to late.., but didn't find any better way of doing requests from within express.
Use
https://www.npmjs.com/package/request and pipe the response out.
Note: XMLHttpRequest's are generally restricted to the same origin.

turn caching off in javascript

Hi all I am trying to turn caching off by
Adding a random value to the query string component of the URL sent with the request message.
I have a server that sends the etag as a string to my client and I want to make sure no caching is going on I already setRequestHeaders but i'm also supposed to add an http request similar to POST /message?x=0.123456789 HTTP/1.1
this is my client code
<html>
<header><title>This is title</title></header>
<body>
<span id="ajaxButton" style="cursor: pointer; text-decoration: underline">
Make a request
</span>
<script type="text/javascript">
(function() {
var httpRequest;
var x= Math.random();
document.getElementById("ajaxButton").onclick = function() { makeRequest('http://localhost:5000/'); };
function makeRequest(url) {
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE
try {
httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {
try {
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {}
}
}
if (!httpRequest) {
alert('Giving up :( Cannot create an XMLHTTP instance');
return false;
}
httpRequest.onreadystatechange = alertContents;
httpRequest.open('GET', url, true);
//httpRequest.setRequestHeader("pragma", "no-cache");
//httpRequest.setRequestHeader("Cache-Control", "no-cache", "no-store");
httpRequest.send();
}
function alertContents() {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
var etagString = httpRequest.responseText;
alert(etagString);
} else {
alert('There was a problem with the request.');
}
}
}
})();
</script>
</body>
</html>
edit for adding errors
XMLHttpRequest cannot load http://localhost:5000/?_0.1909303846769035. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
using node.js I run the server using main.js which is
var http = require('http');
var domain = require('domain');
var root = require('./root'); // do I have to replace root w/ message
var image = require('./image'); // for better readability?
function replyError(res) {
try {
res.writeHead(500);
res.end('Server error.');
} catch (err) {
console.error('Error sending response with code 500.');
}
};
function replyNotFound(res) {
res.writeHead(404);
res.end('not found');
}
function handleRequest(req, res) {
console.log('Handling request for ' + req.url);
if (req.url === '/') {
root.handle(req, res);
}
if (req.url === '/image.png'){
image.handle(req, res);
}
else {
replyNotFound(res);
}
}
var server = http.createServer();
server.on('request', function(req, res) {
var d = domain.create();
d.on('error', function(err) {
console.error(req.url, err.message);
replyError(res);
});
d.run(function() { handleRequest(req, res)});
});
function listen(){
server.listen(5000);
}
root.init(listen);
and inside root.js is
var http = require('http');
var response = require('./response');
var body;
var etag;
exports.handle = function(req, res) {
if (req.headers['if-none-match'] === etag) {
console.log('returning 304');
return response.replyNotModified(res);
}
res.writeHead(200, {'Content-Type': 'text/plain',
'Content-Length': body.length,
"Access-Control-Allow-Origin":"*",
"Access-Control-Allow-Headers":"X-Requested-With",
'ETag' : etag
});
res.end(body);
}
exports.init = function(cb) {
require('fs').readFile('app.html', function(err, data) {
if (err) throw err;
etag = response.generateETag(data); //
body = etag;
console.log("init");
cb();
});
}
/*function generateETag(buffer) {
var shasum = require('crypto').createHash('sha1');
shasum.update(buffer, 'binary');
return shasum.digest('hex');
console.log(shasum.digest('hex'));
}
var replyNotModified = function(res) {
res.writeHead(304);
res.end();
};*/
the errors are in
So, the error that you're getting is to do with cross-origin resource sharing, which has nothing to do with caching or query strings. It looks like you're trying to make AJAX calls from a file:// url, which you can't do.
If you serve the page in question from your Node.js app, that message should go away.
If you can't do that, set up that app to send CORS headers. You can read about CORS in detail at MDN, but the short version is that you need to send a header that looks like this (where otherdomain.com is where the Web page is hosted):
Access-Control-Allow-Origin: http://otherdomain.com
Note that you'll still have to serve the page over HTTP; to my knowledge you can't do AJAX at all from a page loaded via a file:// URL.
You could add '_=' + new Date().getTime(); to the query string of the url. Since it isn't clear whether the url already has a query string attached to it, it's hard to give a more complete answer. It'd be either url += '?_=' + new Date().getTime(); or url += '&_=' + new Date().getTime();.
I'll leave this answer here because it seems to answer the question that the OP was asking. But the solution to the problem the OP was experiencing is Adam Brenecki's answer below.

Categories

Resources