Node.js and the Express Framework
In a previous post I decided to dive into Node.js. Since CodeTunnel is my own personal hobby project I decided it would be a good idea to re-write CodeTunnel in Node for practice and for fun. It has been a bigger undertaking than I originally thought but it's still a lot of fun. I always learn new concepts the best when I try to explain them to other people. To that end I decided that a blog post on each of the technologies from the previous post would be a great way to get experience with each bit.
In this post I want to talk about Node.js and the Express Framework. Node itself as actually rather simple in concept. Once you wrap your mind around the idea of running Javascript on the server like any other server-side language then it becomes a simple transition. One of my biggest hurdles was realizing that I didn't actually know Javascript all that well. One could say that jQuery is partly responsible for keeping me Javascript ignorant. Until now I've rarely used Javascript by itself; jQuery is such an awesome abstraction over Javascript with such great documentation that it's really easy to simply ignore what is actually happening underneath.
I decided to brush up on my Javascript knowledge before I did any more work. Javascript: The Good Parts was an excellent read that helped me to get a lot more knowledge about the language. I still don't completely understand prototyping but I think I have enough of a working knowledge that I can finally begin to fiddle around with some Node. I highly recommend before starting Node.js that you ensure your general Javascript skills are up to snuff. If you know a moderate amount of Javascript then adding the minimal concepts that Node introduces to your brain is rather simple.
Node.js
The first Node concept I had to wrap my head around was the idea that the Node engine itself was also the web host. Hosting a website without IIS just seemed so....weird to me. An example would be the "hello world" code snippet they have on the Node homepage:
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337');
This little code snippet is just plain awesome. It is all the code you need to have a web application in node. If you run this and then go to http://127.0.0.1:1337 in your browser then you will see the simple text "Hello World" printed to the page. I could go into all sorts of detail about how Node is asynchronous and how Node knows not to stop the process while there is a listening server, etc. However, that information is all over the web so here I'm just going to jump ahead and talk about modules.
If you're coming from .NET to Node.js then you can compare Node modules to references in C#. In C# when you need to send an email you use the System.Net.Mail
library. In Node you would pull in a module to accomplish the same thing. Just like in .NET Node has both built in modules and a package manager for downloading community modules. The node package manager is awesome, but I'm not going to go into detail here. Once I understood modules the only thing I needed to learn was how to load them.
In the snippet above they load one of Node's built-in modules called "http" using the require
function. You could relate require
to C#'s using
statement. You assign the results of require
to a variable and you can then use it's functions in your application. In the "hello world" example they use the http.createServer
function to set up a web server and respond to requests. Using modules is easy, but what about writing them? Easy too.
There is a special object within a module called exports
that allows you to expose module functions and properties by attaching them to this object. Create a file called hello.js
and put the following inside it:
exports.sayHello = function () {
console.log('Hello, this action occurred in a custom module.');
};
Then in your main app.js
file simple do the following:
var hello = require('./hello');
hello.sayHello();
Running app.js
will print "Hello, this action occurred in a custom module." to the console window. Notice that because we didn't start a web server the process ends after it runs the module function. Honestly with just this little bit of information I already felt ready to start building something. I created a new project in WebStorm and suddenly realized that with Node I was completely responsible for handling the entire request from the client. I even had to write response headers manually as you can see in the "hello world" example. Well this is hardly a web development framework at this point; it's a web server sure, but I need my beloved MVC-style framework that I have grown so accustomed to.
Express to the rescue!
It just so happens that the Node community is already on top of things. There exists a web development MVC framework for Node called Express. Express brings TONS of tools to the table to help out with development. To install Express we need to use the Node Package Manager (NPM) and run npm install express -g
. The "-g" installs express globally so that we can use it in any projects, not just our current one. Once express is installed globally then we can use the express
command at the command line. On the command line move to the directory for your application and run the express
command. You can run the command without any parameters and accept the default setup or you can customize things such as adding session support, changing the view engine, or even choosing a stylesheet engine. I'm not going to go into detail here about everything that Express brings but I would like to show you the app.js
file that is generated by running this command.
var express = require('express')
, routes = require('./routes')
, user = require('./routes/user')
, http = require('http')
, path = require('path');
var app = express();
app.configure(function(){
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
});
app.configure('development', function(){
app.use(express.errorHandler());
});
app.get('/', routes.index);
app.get('/users', user.list);
http.createServer(app).listen(app.get('port'), function(){
console.log("Express server listening on port " + app.get('port'));
});
Right from the start you can see that Express added a bunch of modules for us and ran some funky configure
function which we'll get to in a minute. If you jump to the bottom of the file you'll notice that we have a couple routes defined. There is far to much detail about routing with Express for me to get into here, but suffice it to say it should look pretty familiar if you've used ASP.NET MVC. You can do pretty much the same things you could do in .NET with this routing system, including capture variables. The cool part about this system though is that instead of using some arbitrary convention to map these routes to action methods, you literally connect them directly to the function that will handle the request.
In the default app.js
file generated by express they put route handler functions into separate files/modules and reference them so that the routes in app.js
don't get too cluttered. However, just so you can get a clearer picture of how these routes work you could replace app.get('/users', user.list);
with something like this:
app.get('/hello', function (req, res) {
res.send('Hello from an Express route!');
});
Hopefully that is pretty self-explanatory, but just in case let's briefly touch on what is happening here. app.get
takes two parameters: the first parameter is the route you want to match on, the second is a function to handle the request when it matches the route. Notice that the request handler function takes a req
(request) and res
(response) parameters. req
contains information provided by both Node itself and the Express framework about the incoming request. res
allows access to information and actions related to the response we are about to send back to the client. In our example above we use the res.send()
function to send a string to the client that will be rendered in the browser.
Hopefully by now you are starting to see just how awesome Express is. It contains so much that I'm not even totally competent with it yet, but I am sure over time that will improve. I'll be honest though, if Express didn't exist then Node.js would be nothing more than a toy to me; with Express however, I can see the real power of Node and I am excited to begin deploying applications written in Node.