I love NodeJS

So NodeJS has become all the rage in the development world recently, especially amongst those developers that use a lot of JavaScript and it certainly presents some interesting opportunities for those that know what they are doing with it.

Even more so if you couple it with other solid JavaScript libraries like SpineJS.

Essentially speaking for those of you that don’t know, JavaScript is usually a client side implementation in the browser to add extra functionality or small bits of programming logic. Think things like Jquery. In browser, adds functionality, is used as a solid library for manipulating elements and data on a page, and can be used to provide some very nice client-side validation.

NodeJS is on a whole other level.

NodeJS the Serverside JavaScript Framework

Node is server side JS and is used to write Java Applications and acts as a solid framework for building applications on. Think python.

And today I intend to give you a little demonstration of just what you can do. In 37 lines I am going to create a web server that will function and serve static files (no fancy logic in this one). You can think of it as a portable web server on the go.

var http = require("http"),
 url = require("url"),
 path = require("path"),
 fs = require("fs")
 port = process.argv[2] || 8888;

So first we initialise some variables. These are Node includes for the most part dictating which sub libraries of Node we want to include in our application. HTTP is used to handle HTTP requests. URL manipulates URL data, PATH allows us to manipulate local data paths (needed for finding files) and FS is included to read out files and serve them back out.

Now the beauty of Node is it’s designed to be non-blocking, and therefore can handle multiple asynchronous requests in one go. And it is with that in mind that the application makes a lot of use of callbacks, where the functions listen for an activity and wait to respond to it.

http.createServer(function(request, response) {}.listen(parseInt(port, 10));

BAM. That line has just made a http listener, that will listen for http requests coming in on the port we specified in the Variables above (8888). At the moment though it will literally do nothing except listen to a request.

We also want a line following that to actually provide a start to the application and give some feedback on the server. So we add:

console.log("Static file server running at\n => http://localhost:" + port + "/\nCTRL + C to shutdown");

That will write to the console, letting us know that the server has actually started, and give us some details like the port we have specified.

Node running our Server.js file

Ok time to get some application logic in there.

http.createServer(function(request, response) {
 var uri = url.parse(request.url).pathname
 , filename = path.join(process.cwd(),"public/", uri);
 }).listen(parseInt(port, 10));

What we have now is listener that will look for incoming HTTP requests on port 8888 on the server and will attempt to parse the URL that is provided removing the host information to get a path string to a file, which it will append to the node instances current working directory.

So if my Node app is running on d:/node and I send a request to local host that is http://localhost:8888/files/ it will amend the path above to be d:/node/files/.  Pretty nifty.

So now for a bit of validation. We amend the http.createServer function to the following.

http.createServer(function(request, response) {
 var uri = url.parse(request.url).pathname
 , filename = path.join(process.cwd(),"public/", uri);
 path.exists(filename, function(exists) {
 if(!exists) {
 response.writeHead(404, {"Content-Type": "text/plain"});
 response.write("404 Not Found\n");
 response.end();
 return;
 }
 });
 }).listen(parseInt(port, 10));

Excellent. Now we have some validation in there. path.exists checks the path variable we assign to filename to see if it exists. If it doesn’t it ends the request and responds with a 404 error. The response.writeHead function tells the page that made the request the type of content to expect. Then we write to the page our 404 message, finishing by ending the response.

A 404 generated by node when it can't find the file we requested

Next we want to start serving some files back to users.

Amend the createServer function as follows:

http.createServer(function(request, response) {
 var uri = url.parse(request.url).pathname
 , filename = path.join(process.cwd(),"public/", uri);
path.exists(filename, function(exists) {
 if(!exists) {
 response.writeHead(404, {"Content-Type": "text/plain"});
 response.write("404 Not Found\n");
 response.end();
 return;
 }
if (fs.statSync(filename).isDirectory()) filename += '/index.html';
 });
}).listen(parseInt(port, 10));

Ok. Standard HTML time. We need to check to see if we are looking at a directory or at a file in the URL request.

http://localhost:8888/files/ is looking at a directory, so we would want to find the index of that directory. The line we just added uses the file system (fs) library we loaded to check if it is a directory. In this case it is, so it appends the path with a file name. Index.html. The standard root for all folders. http://localhost:8888/files/fred.html would not be a directory so it would leave the string as is.

Now we have a file that we are looking for we need to serve it back to the user at the other end. Amend the server function to this:

http.createServer(function(request, response) {
var uri = url.parse(request.url).pathname
 , filename = path.join(process.cwd(),"public/", uri);
path.exists(filename, function(exists) {
 if(!exists) {
 response.writeHead(404, {"Content-Type": "text/plain"});
 response.write("404 Not Found\n");
 response.end();
 return;
 }
if (fs.statSync(filename).isDirectory()) filename += '/index.html';
    fs.readFile(filename, "binary", function(err, file) {
 if(err) {
 response.writeHead(500, {"Content-Type": "text/plain"});
 response.write(err + "\n");
 response.end();
 return;
 }
      response.writeHead(200);
 response.write(file, "binary");
 response.end();
 });
 });
 }).listen(parseInt(port, 10));

Ok that was a nice chunk. So what this section is now doing is reading the file given by our filename string using the type binary.

It checks to see if the file can be read (if(err)). If the statement produces an error it sends a 500 server error response back to the user on the other end. If it doesn’t produce an error it sends the file back as binary, resulting in one web page being displayed.

One successfully loaded webpage. You'll note that the HTTP requests for CSS files and images have also been successful and returned as well

BAM. In 37 lines of JavaScript we have just created a working web server.

You can further extend this by adding other libraries like SpineJS to make fully JS MVC applications that will return more dynamic content (using JSON and then parsing it with AJAX requests).

It’s amazing what you can do with some languages, and that is why I love the NodeJS framework.

Go get it and go play!

Dave the Keeper of Nodes.

Advertisements
Tagged , , , , , , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: