News

Build a web server with Node.js

Discover how to build a custom 'self-assembly' lightweight web server using the Node.js javascript library

NodeJS800

Web servers don’t need to be big, general-purpose applications. Over the years they’ve become more complex, delivering all kinds of content to your browser.

But what if you need something focused? Internet Information Server and Apache are overkill, and even next-gen servers like nginx require significant resources. That’s where Node.js comes in. Instead of taking an existing web server and letting you shoehorn your application around its features and APIs, Node.js takes a very different approach. You don’t have a server, you just have a kit of parts that you can assemble into your own custom-built web appliance that handles the inputs and outputs you’ve designed – it’s a router that takes inputs and gives outputs, an ‘if this, then that’ tool for your web applications.

Another advantage is, Instead of learning C++ to build extensions to Apache, you’re writing a server in the web’s own programming language – JavaScript.

DOWNLOAD TUTORIAL FILE

Getting to Node

Once installed, Node.js needs code to work. Unlike the familiar web servers, you’ll need to write JavaScript to handle requests, building your own server from the Node.js framework. Start by creating a file called ‘server.js’. This is the heart of a Node.js application, so declare a protocol and a port.

001 var http = require('http');
002 var port = process.env.port || 8888;

Creating a server

Our first two lines of code have declared two key variables – the protocol our server is listening for, and the port it’s listening on. We can now start to add the code to handle the requests, and to deliver a response. We can do this in a single line, with a nested function in a createServer object.

001 http.createServer(function (request, response) {
002 response.writeHead(200, {'Content-Type': 'text/plain'});
003 response.end('Hello Web Designern');
004 }).listen(port);

Run a server

The code we’ve just added implements a basic HTTP response, and delivers a snippet of content to a page. You’ll need to implement code for all the HTTP responses you want to add to a server, which means you’ll need more than just a single piece of code. Save the code as ‘server.js’ and run it.

001 node server.js

Getting switched

A good way of thinking about Node.js is as a switch. Your code takes inputs from a port, and sends the results back to the requester over the web. It’s event-driven – nothing happens unless it’s triggered, with actions handled by functions. We can make our code a little clearer, with a function for the request handler.

001 var http = require('http');
002 var port = process.env.port || 8888;
003 function httpRequest(request, response) {
004 response.writeHead(200, {'Content-Type': 'text/plain'});
005 response.write('Hello Web Designern');
006 response.end();
007 }
008 http.createServer(httpRequest).listen(port);

Making things simpler

Working with raw Node.js is, to be really quite honest with you, pretty complex. You need to understand just how a web server works in order to handle all the responses your service is going to need to need to give – and how to structure the HTTP content that gets returned. A good alternative option is to use Express, a set of libraries that make the process of building a server from scratch a lot easier. Start by installing Express using Node.js’ built-in package manager.

001 $npm install-g express 

Rewriting with Express

Using Express can simplify a lot of Node.js code. Instead of having to write all the HTTP responses for a server, Express handles it for you. You just need to define the server and its content. There’s a lot less code to write, and even less keeping track. Our simple app becomes:

001 var app = require('express').createServer();
002 app.get('/', function(request, response){
003 response.send('Hello Web Designer');
004 }
005 app.listen(8888);

Express for MVC

Express is more than just a form of shorthand for building Node.js applications, it’s a full Model View Controller framework, like the open-source Ruby on Rails or Microsoft’s ASP.NET MVC. You can use it to automatically generate the framework for an application, which you can then customise and use as the basis for your code. Start by creating an application and install the appropriate dependencies.

001 $express /webdesigner && cd /webdesigner
002 $npm install-d

Cutomise Express

Now that we have built our Express application framework, we can start to customise it. We’ll need to edit the view that’s used by Express to display the index page, which is handled by Node.js’ Jade templating engine – which separates code and design. In the views directory open ‘index.jade’ in a text editor.

001 h1= title
002 p Welcome to #{title}

A quick look at Jade

Jade turns out to be a very important tool for anyone building MVC applications in Express and Node.js. It’s a simple template tool that displays content from our code. In the routes folder created by Express, open ‘index.js’. You’ll see a title variable – currently set to Express – which is used in the Jade template. Change it as follows:

001 exports.index = function(req, res){
002 res.render('index', { title: 'Web Designer' })
003 }; 

Adding a new route (1)

Node.js works as a switching engine, taking a URL input and delivering it to the appropriate output. Each input/output pair is called a route, and needs to be built into your application code. As we’re using Express, we’ll first need to modify our server code, to add the switching code we need. Edit the routes section as follows:

001 // Routes
002 
003 app.get('/', routes.index);
004 app.get('/web', web.web); 

Adding a new route (2)

We can now add a new section of code in the routes directory. It’s always sensible to keep the sections of an MVC application in specific folders, as it makes them more manageable – and your job noticeably easier. You’ll note that we’re calling routes.web in the main server code, so we need to create the corresponding web.js file.

001 exports.web = function(req, res){
002 res.render('web', { title: 'A second page' })
003 };

Adding a new route (3)

You might think that’s all you need to do to get a new route working, but there’s more to do yet. In the head of our main server we’re going to need to add some more code to declare a variable for our new route file. Add a require line for /routes/web as follows.

001 var express = require('express')
002 , routes = require('./routes')
003 , web = require('./routes/web');

Adding a new route (4)

We’re now ready to add an additional template in the views directory for our new web page. We can use the existing index.jade file as the basis for the new template. It doesn’t have to be particularly complicated, just a title and some body text. Create ‘web.jade’, and add the following content.

001 h1= title
002 p Welcome to page 2

Styling the pages

Express uses the Jade Node.js styling engine to handle template layout. We’ve created basic Jade templates for our pages, now we need to look at the master layout.jade file created by Express. This is where we can put site- (or section-) wide style information, including CSS and other HTML5 features. Add HTML formatting as needed.

001 !!!
002 html
003 head
004 title= title
005 link(rel='stylesheet', href='/stylesheets/style.css')
006 body!= body

Structuring Jade

If you look closely at a Jade template, and the corresponding code, you can start to see how the two fit together. Values passed to and from a Node.js function are rendered in pages, and elements prefixed by # are treated as DIVs for use with a stylesheet. If we wanted to render two pieces of text with an appropriate DIV:

001 #tag #{title} #{message};
Which displays as
001
[content of title] [content of message]



Passing values (1)

Now that we have the basic structure of our server we can start to build it into an application. We are going to write a simple server function that delivers a DNS lookup for a server name sent as part of a URL. Start by defining a new route for our DNS function.

001 var express = require('express')
002 , routes = require('./routes')
003 , lookup = require('./routes/lookup);

Passing values (2)

Add code to send a value to a new ‘lookup.js’ file that we’re going to add to the routes folder, much like we did the file for the second page. However, this time we’re sending more than just a call to a URL, we’re also sending a value to parse as part of the URL we’re using to call the server.

001 app.get('/', routes.index);
002 app.get('/web', web.web);
003 app.get('/lookup/:value, lookup.lookup);

Passing values (3)

We can now start to create our new route. You’ll notice that we’ve been using app.get for all our routes so far. That’s because Node.js implements HTTP’s POST and GET functions. We’re using GET as we’re not working with forms, so we can use a query string to pass values from the browser to our code. Create a lookup.js file in the routes folder.
001 exports.lookup = function(req, res){
002 var dnsname = req.query['dnslookup'];
003 res.render('lookup', {title: 'DNS lookup', dns: dnsname});
004 };



Passing values (4)

The most important bit of code in our lookup.js file is the req.query statement. That’s where we take the query string dnslookup value from the calling URL and convert it into a string, called dnsname string, which we can then use in our application, initially just displaying it in a jade template.

001 var dnsname = req.query['dnslookup'];

Passing values (5)

Now that we’ve extracted our data from our URL (eg http:// http://localhost:81/lookup?dnslookup=www.bbc.co.uk), we are now able to go ahead and display it. We’ve already written ourselves a res.render statement that delivers a title and a new variable, dns, set to the dnsname string to a lookup.jade template. We can now write a simple template to handle the call. Note the #{dns} statement. This will render the content of the dns variable, displaying the URL we want to see, which is www.bbc.co.uk.

001 h1= title
002 #{dns}
003 

Looking up a dns value

Node.js contains a wide selection of functions we can use in our applications – functions that are needed in a server. One set handles dns lookups, both forward and reverse. As we’re extracting a domain name from our query string, we can do a reverse lookup to display the IP address of the domain. Rewrite lookup.js to add the following code:

001 exports.lookup = function(req, res){ 
002 var dns = require('dns');
003 var dnsname = req.query['dnslookup'];
004 dns.lookup(dnsname,function(err, address) { 
005 if(err) { 
006 console.log(err.toString()); 
007 return;
008 }
009 dnsvalue = address; 
010 }); 
011 res.render('lookup', {title: 'DNS lookup', dnstxt: dnsname, dnsnum: dnsvalue});
012 };

Displaying the result

We now need to modify our lookup.jade template to display the results. We’ve already put a structure in place with our call to res.render, adding a variable dnsnum that’s set to the dnsvalue string and delivered by the dns.lookup function. It’s simple, then, to go ahead and just add a new line to the existing template:

001 h1= title
002 #{dnstxt}
003 #{dnsnum}

CODE LIBRARY

INSIDE SERVER.JS

The heart of a Node.js application is the server.js file. It’s here you define the structure of your application, and here that you start to put together the routes that translate URLs into function calls

001 // Modules
002 
003 var express = require('express')
004 , routes = require('./routes')
005 , web = require('./routes/web')
006 , lookup = require('./routes/lookup');
007 var app = module.exports = express. createServer();
008 
009 // Configuration
010 
011 app.configure(function(){
012 app.set('views', __dirname + '/views');
013 app.set('view engine', 'jade');
014 app.use(express.bodyParser());
015 app.use(express.methodOverride());
016 app.use(app.router);
017 app.use(express.static(__dirname + '/ public'));
018 });
019 
020 app.configure('development', function(){
021 app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
022 });
023 
024 app.configure('production', function(){
025 app.use(express.errorHandler());
026 });
027 
028 // Routes
029 
030 app.get('/', routes.index);
031 app.get('/web', web.web);
032 app.get('/lookup', lookup.lookup);
033 
034 app.listen(process.env.port);
×