Node.js Express | JQuery Nothing happens on client when getting a JSON - javascript

I want to receive on an HTML5 website JSON from a PostgreSQL database. So, on the server side I use node-postgres module for DB connection and also express module for communication.
The problem is that in the html i am not seeing any alert when getting the data from the server. The alert isn't even thrown.
this is how my code is so far, for anyone that could help:
serverside
var express = require('express');
var app = express();
app.get('/data', function(req, res){
var pg = require('pg');
var conString = "postgres://postgres:postgres2#localhost/spots";
var client = new pg.Client(conString);
client.connect(function(err) {
if(err) {
res.send('could not connect to postgres');
}
client.query('SELECT * from spots_json where id=3276', function(err, result) {
if(err) {
res.send('error running query');
}
res.set("Content-Type", 'text/javascript'); // i added this to avoid the "Resource interpreted as Script but transferred with MIME type text/html" message
res.send(JSON.stringify(result.rows[0].json));
client.end();
});
});
});
app.listen(3000);
clientside
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no"></meta>
<meta charset="utf-8"></meta>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.js" ></script>
<script>
$.get('http://localhost:3000/data?callback=?',{}, function(data){
alert(data.type);
},"json");
</script>
</head>
<body>
<div id="map-canvas"></div>
</body>
</html>
The client is now executed on http://localhost:8888/prueba/prueba.html
Im getting a js with the following Response:
"{\"type\":\"Point\",\"coordinates\":[-2.994783,43.389217]}"
The Response can be seen in the following screenshot:

result.rows[0].json is not an object, it is a string. You don't need to stringify it:
res.send(result.rows[0].json);
Edit:
If you use two servers on different ports you will need to use JSONP. jQuery makes this simple on the client side, but you will need to implement it in your server (example):
if(req.query.callback) {
res.send(req.query.callback + '(' + result.rows[0].json + ');');
} else {
res.send(result.rows[0].json);
}
By the way, you need to return if you encounter an error in one of your callbacks to prevent subsequent code from being executed.
if(err) {
res.end('error message');
return;
// Or shorter: return res.end('error message');
}

Related

How do I define Watershed in Node.js?

When I execute the following code, I get the error: Reference Error: Watershed is not defined. How can I define it? Do I need a module to be installed for it?
var restify=require('restify');
var ws= new Watershed();
var server=restify.createServer();
server.get('websocket/attach', function upgradeRoute(req, res, next){
if(!res.claimUpgrade){
next(new Error("Connection must be upgraded."));
return;
}
var upgrade=res.claimUpgrade();
var shed=ws.accept(req, upgrade.socket, upgrade.head);
shed.on('text', function (msg){
console.log("The message is: "+msg);
});
shed.send("hello there");
next(false);
});
server.listen(8081, function(){
console.log('%s listening at %s', server.name, server.url);
});
There is also a section of the restify doc that mentioned how to handle the ability to upgrade sockets. I just struggled with this for an emarrassingly long time and thought I'd share the simple solution. In addtion the #Dibu Raj reply, you also need to create your restify server with the handleUpgrades option set to true. Here is a complete example to make restify work with websocket upgrades and watershed:
'use strict';
var restify = require('restify');
var watershed = require('watershed');
var ws = new watershed.Watershed();
var server = restify.createServer({
handleUpgrades: true
});
server.get('/websocket/attach', function (req, res, next) {
if (!res.claimUpgrade) {
next(new Error('Connection Must Upgrade For WebSockets'));
return;
}
console.log("upgrade claimed");
var upgrade = res.claimUpgrade();
var shed = ws.accept(req, upgrade.socket, upgrade.head);
shed.on('text', function(msg) {
console.log('Received message from websocket client: ' + msg);
});
shed.send('hello there!');
next(false);
});
//For a complete sample, here is an ability to serve up a subfolder:
server.get(/\/test\/?.*/, restify.serveStatic({
directory: './static',
default: 'index.html'
}));
server.listen(8080, function() {
console.log('%s listening at %s', server.name, server.url);
});
For an html page to test your new nodejs websocket server: write this html below into a file at ./static/test/index.html - point your browser to http://localhost:8080/test/index.html - open your browser debug console to see the message exchange.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Web Socket test area</title>
<meta name="description" content="Web Socket tester">
<meta name="author" content="Tim">
</head>
<body>
Test Text.
<script>
(function() {
console.log("Opening connection");
var exampleSocket = new WebSocket("ws:/localhost:8080/websocket/attach");
exampleSocket.onopen = function (event) {
console.log("Opened socket!");
exampleSocket.send("Here's some text that the server is urgently awaiting!");
};
exampleSocket.onmessage = function (event) {
console.log("return:", event.data);
exampleSocket.close();
}
})();
</script>
</body>
</html>
Your browser log will look something like this:
07:05:05.357 index.html:18 Opening connection
07:05:05.480 index.html:22 Opened socket!
07:05:05.481 index.html:26 return: hello there!
And your node log will look like:
restify listening at http://[::]:8080
client connected!
Rest service called started
upgrade claimed
Received message from websocket client: Here's some text that the server is urgently awaiting!
Documentation for this found at:
http://restify.com/#upgrade-requests
You should include the watershed library
var Watershed = require('lib/watershed').Watershed;

Simple node.js server that sends html+css as response

I've created basic http server that sends html file as response. How can I send css file as well so client using browser will see a html using css ?
The code I have:
var http = require('http');
var fs = require('fs');
var htmlFile;
fs.readFile('./AppClient.html', function(err, data) {
if (err){
throw err;
}
htmlFile = data;
});
var server = http.createServer(function (request, response) {
response.writeHead(200, {"Content-Type": "text/html"});
response.end(htmlFile);
});
//Listen on port 8000, IP defaults to 127.0.0.1
server.listen(8000);
console.log("Server running at http://127.0.0.1:8000/");
What I have tried(it seems it does not work - client sees only css file content here):
var http = require('http');
var fs = require('fs');
var htmlFile;
var cssFile;
fs.readFile('./AppClient.html', function(err, data) {
if (err){
throw err;
}
htmlFile = data;
});
fs.readFile('./AppClientStyle.css', function(err, data) {
if (err){
throw err;
}
cssFile = data;
});
var server = http.createServer(function (request, response) {
response.writeHead(200, {"Content-Type": "text/css"});
response.write(cssFile);
response.end();
response.writeHead(200, {"Content-Type": "text/html"});
response.write(htmlFile);
response.end();
});
//Listen on port 8000, IP defaults to 127.0.0.1
server.listen(8000);
console.log("Server running at http://127.0.0.1:8000/");
html file:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" type="text/css" href="AppClientStyle.css">
</head>
<body>
<div class=middleScreen>
<p id="p1">Random text</p>
</div>
</body>
</html>
css file :
#CHARSET "UTF-8";
.middleScreen{
text-align:center;
margin-top:10%;
}
I don't want to use express here(it is just for learning purpose)
What you have written in your first snippet is a web server that responds with the body of your HTML file regardless of what URI the browser requests.
That's all nice and well, but then with the second snippet, you're trying to send a second document to a closed response handle. To understand why this doesn't work, you have to understand how HTTP works. HTTP is (for the most part) a request->response type protocol. That is, the browser asks for something and the server sends that thing, or an error message of some sort, back to the browser. (I'll skip over keep-alive and methods that allow the server to push content to the browser--those are all far beyond the simple learning purpose you seem to have in mind here.) Suffice it to say that it is inappropriate to send a second response to the browser when it hasn't asked for it.
So how do you get the browser to ask for a second document? Well, that's easy enough... in your HTML file you probably have a <link rel="stylesheet" href="AppClientStyle.css"> tag. This will cause the browser to make a request to your server asking it for AppClientStyle.css. You can handle this by adding a switch or if to your createServer code to perform a different action based on the URL the browser requests.
var server = http.createServer(function (request, response) {
switch (request.url) {
case "/AppClientStyle.css" :
response.writeHead(200, {"Content-Type": "text/css"});
response.write(cssFile);
break;
default :
response.writeHead(200, {"Content-Type": "text/html"});
response.write(htmlFile);
});
response.end();
}
So, first, when you access your server at http://localhost:8000 you will be sent your html file. Then the contents of that file will trigger the browser to ask for http://localhost:8000/AppClientStyle.css
Note that you can make your server far more flexible by serving any file that exists in your project directory:
var server = http.createServer(function (request, response) {
fs.readFile('./' + request.url, function(err, data) {
if (!err) {
var dotoffset = request.url.lastIndexOf('.');
var mimetype = dotoffset == -1
? 'text/plain'
: {
'.html' : 'text/html',
'.ico' : 'image/x-icon',
'.jpg' : 'image/jpeg',
'.png' : 'image/png',
'.gif' : 'image/gif',
'.css' : 'text/css',
'.js' : 'text/javascript'
}[ request.url.substr(dotoffset) ];
response.setHeader('Content-type' , mimetype);
response.end(data);
console.log( request.url, mimetype );
} else {
console.log ('file not found: ' + request.url);
response.writeHead(404, "Not Found");
response.end();
}
});
})
Start this in the same directory as your HTML and CSS files. The above is simplistic, error-prone and INSECURE. But it should be sufficient for your own learning or local development purposes.
Keep in mind that all the above is far less succinct than just using Express. In fact, I'm not sure why you wouldn't want to use Express, so I'm going to try to convince you to try it:
$ npm install express
$ mkdir www
$ mv AppClientStyle.css www/
$ mv AppClient.html www/index.html
Your script will look like: (Borrowed from Express Hello World)
var express = require('express')
var app = express()
app.use(express.static('www'));
var server = app.listen(8000, function () {
var host = server.address().address
var port = server.address().port
console.log('Express app listening at http://%s:%s', host, port)
})
Then run your script and point your browser to http://localhost:8000. It really is that painless.
Integrate the CSS right into your AppClient.html file. There are different ways to do so:
External CSS file
Create a styles.css file (or any other file name) in the same directory as your html file. Then add
<link rel="stylesheet" type="text/css" href="styles.css">
to your <head> section of your HTML document.
OR
Right in your HTML file
Add a
<style>
YOUR STYLES RIGHT HERE
</style>
to your <head> section of your HTML document.

Node.js Express | Always getting null when trying to get a JSON

I am very new to node.js and I want to receive on an HTML5 website JSON from a PostgreSQL database. So, on the server side I use node-postgres module for DB connection and also express module for communication. The PostgreSQL query is returning a JSON object.
Server-side:
var express = require('express');
var app = express();
app.get('/data', function(req, res){
var pg = require('pg');
var conString = "postgres://postgres:postgres2#localhost/spots";
var client = new pg.Client(conString);
client.connect(function(err) {
if(err) {
res.send('could not connect to postgres');
}
client.query('SELECT * from spots_json where id=3276', function(err, result) {
if(err) {
res.send('error running query');
}
res.send(JSON.stringify(result.rows[0].json));
client.end();
});
});
});
app.listen(3000);
Client-side:
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.js" ></script>
<script>
$.get('http://localhost:3000/data',{}, function(data){
alert(JSON.parse(data));
},"json");
</script>
</head>
<body>
<div id="map-canvas"></div>
</body>
</html>
If I navigate to http://localhost:3000/data on the browser I get:
{\"type\":\"Point\",\"coordinates\":[-2.994783,43.389217]}
So I see that the server is sending the stringified JSON properly, but on the client I always get null data. I must have some misconception.
Ok this is how my code is so far, for anyone that could help:
serverside
var express = require('express');
var app = express();
app.get('/data', function(req, res){
var pg = require('pg');
var conString = "postgres://postgres:postgres2#localhost/spots";
var client = new pg.Client(conString);
client.connect(function(err) {
if(err) {
res.send('could not connect to postgres');
}
client.query('SELECT * from spots_json where id=3276', function(err, result) {
if(err) {
res.send('error running query');
}
res.set("Content-Type", 'text/javascript'); // i added this to avoid the "Resource interpreted as Script but transferred with MIME type text/html" message
res.send(JSON.stringify(result.rows[0].json));
client.end();
});
});
});
app.listen(3000);
clientside
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no"></meta>
<meta charset="utf-8"></meta>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.js" ></script>
<script>
$.get('http://localhost:3000/data?callback=?',{}, function(data){
alert(data.type);
},"json");
</script>
</head>
<body>
<div id="map-canvas"></div>
</body>
</html>
The client is now executed on http://localhost:8888/prueba/prueba.html
Im getting a js with the following Response:
"{\"type\":\"Point\",\"coordinates\":[-2.994783,43.389217]}"
The Response can be seen in the following screenshot:
https://www.dropbox.com/s/zi4c5pqnbctf548/pantallazo.png
But now the alert isn't even shown...
I think i need some light with this.
The data is already an object when you get it, not a string. So JSON.parse fails because you gave it an object when it was expecting a string. To verify, change
alert(JSON.parse(data));
to
alert(data.type);
and you should get "Point"
The reason you already have an object is because of the "json" parameter you provided to $.get. If you change that to "html" you will get a string back instead which you could then parse out into a JSON object.
I think you should not try to stringify your result when you put it in the response object.
Just put it entirely it will automaticaly that way :
res.set("Content-Type", 'application/json');
res.json(result.rows[0].json);
That is the right way to send information through REST APIs.
Then in your client side code, I don't know how it works but it should accept json natively.

How to set Angular JS $resource path (I'm getting 404s here)

I'm a noob to AngularJS and trying to set up a simple webapp in order to test, if the framework suites our needs. I've read the API reference and did the tutorial. Unfortunately the way path and locations are set and handled on $resource is not quite well explained there.
The problem I am facing is that I always get a 404 when I give $resource the relative path as described in the tutorial.
Here is my set up:
I have cloned the AngularJS phone cat app and threw away their phone stuff but made use of their structure to bring in my own logic. My index.html looks as follows:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>testapp</title>
<link rel="stylesheet" href="css/bootstrap.css">
<script src="lib/angular/angular.js"></script>
<script src="lib/angular/angular-resource.js"></script>
<script src="js/app.js"></script>
<script src="js/controllers.js"></script>
<script src="js/filters.js"></script>
<script src="js/services.js"></script>
</head>
<body ng-app="testapp">
<div class="navbar">
<div class="navbar-inner">
<a class="brand" href="#">Testapp using AngularJS</a>
</div>
</div>
<div ng-view></div>
</body>
First trouble was that AngularJS doesn't seem to give any advice on how to oauth to a RESTful API, and their tutorial only gives a "dream scenario" of a server delivering hard-coded JSON, so I have hacked into their web-server.js in order to let the node.js server handle the API calls and return the resulting JSON. For oauth I did so successfully, yet for further API calls, it doesn't work.
Here's my hack:
StaticServlet.prototype.handleRequest = function(req, res) {
var self = this;
var path = ('./' + req.url.pathname).replace('//','/').replace(/%(..)/g, function(match, hex){
return String.fromCharCode(parseInt(hex, 16));
});
var parts = path.split('/');
if (parts[parts.length-1].charAt(0) === '.')
return self.sendForbidden_(req, res, path);
/* Hack for RESTful API calls. */
var post = '';
var query = qs.parse(req.url);
if (req.method === 'POST') {
var body = '';
req.on('data', function(data) {
body += data;
});
req.on('end', function () {
post = JSON.parse(body);
console.log(post);
// method name is part of the parameters
// apiRequests is the module handling the API requests
apiRequests[post.method](post, res);
});
} else if (query.api === 'api') {
var query = qs.parse(queryString);
// method name is part of the parameters
// apiRequests is the module handling the API requests
apiRequests[query.method](queryString, res);
} else {
fs.stat(path, function(err, stat) {
if (err)
return self.sendMissing_(req, res, path);
if (stat.isDirectory())
return self.sendDirectory_(req, res, path);
return self.sendFile_(req, res, path);
});
}
}
It's really just an ugly hack, but anyways. The login POST request is delegated to an oauth call and the api GET requests are delegated to the proper api request methods, the rest is handled the same way as web-server.js did before.
The trouble is, the handleRequest method is never called.
Here is my client side service code making the call:
return {
fetchCommunications : function ($scope) {
var parameters = {
'api': 'api',
'method': 'communications',
'bearer':userData["access_token"],
'chiffre':userData["chiffre"]
}
var resource = {
r : $resource('communications', {}, {
query: {method:'GET', params:parameters}
})
}
var d = resource.r.query();
console.log("Communications: " + d);
return d;
}
And this is the error message from the server console:
GET /app/communications?api=api&bearer=d6a348ea-0fe5-46fb-9b5e-13d3343c368d&chiffre=0000006F&method=communications Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22
404 Not Found: /app/communications
This is exactly the path I'd expect to be called - but why is it 404?
I can avoid the 404 by configuring $resource like this:
var resource = {
r : $resource('index.html#/communications', {}, {
query: {method:'GET', params:parameters}
})
Which doesn't work either, since everything after the hash is omitted from the path. Besides, why would I need to have index.html within the path?
I have the feeling that I am missing something pretty obvious here and am therefore doing something pretty dumb. Anyone with any ideas? Is it something related to the configuration of node.js (never had this trouble before)?
Many thanks in advance!

how to send messages using socket.io

I want to use socket.io and node as a layer for my "push notification feature", so I'm running both apache and node.
I have the following code on my server (node)
var app = require('http').createServer(handler)
, io = require('C:/path/to/file/socket.io').listen(app)
, fs = require('fs');
app.listen(8080);
function handler(req, res) {
console.log(req);
fs.readFile('C:/path/to/file/index.html',
function (err, data) {
if (err) {
console.log(err);
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}
io.sockets.on('connection', function (socket) {
socket.on('my event', function (msg) {
console.log("DATA!!!");
});
});
the page is then served by apache from localhost without 8080 port
and on the client I have the following code:
var socket = io.connect('http://localhost:8080');
and when a button is clicked:
socket.emit('my event', {data:"some data"});
I see nothing on the node console ... why is that? cross domain issue?
Update:
it works just fine on safari 5.1.5 and even IE 9, but not on chrome(18.0.1025.151) or firefox (11.0) ... what am I missing?
here is the node log:
info - socket.io started
debug - served static content /socket.io.js
debug - client authorized
info - handshake authorized 4944162402088095824
debug - setting request GET /socket.io/1/websocket/4944162402088095824
debug - set heartbeat interval for client 4944162402088095824
debug - client authorized for
debug - websocket writing 1::
debug - setting request GET /socket.io/1/xhr-polling/4944162402088095824?t=13
33977095905
debug - setting poll timeout
debug - discarding transport
debug - cleared heartbeat interval for client 4944162402088095824
That should work fine, just make sure that in your index.html you have :
<script src="http://localhost:8080/socket.io/socket.io.js"></script>
also, since you're serving your page via Apache, you really don't need the handler and the http server in you node file.
this should work just fine :
var io = require('socket.io').listen(8080);
io.sockets.on('connection', function (socket) {
socket.on('my event', function (msg) {
console.log("DATA!!!");
});
});
and for the index.html :
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello World!</title>
<meta charset="utf-8">
<script src="http://localhost:8080/socket.io/socket.io.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var socket = io.connect('http://localhost:8080');
$("#button").click(function() {
socket.emit('my event' ,"Hello World!");
})
})
</script>
</head>
<body>
<button type="button" id='button'>Send Message</button>
</body>
</html>
Edit: This works in both Firefox and Chrome.

Categories

Resources