Now that we have built a router of our own and understand the basics of Node.js, it is time to get introduced to one of the most widely-used frameworks for Node.js, Express (http://expressjs.com). Node.js provides the infrastructural components to build a web application, but there is too much stuff to handle. Therein lies the role of the web frameworks. There are quite a few web frameworks that provide a higher level of abstraction for building applications on Node. You can see a list of most of them here:
https://github.com/joyent/node/wiki/Modules#wiki-web-frameworks-full
Express is a web application framework for Node, built over the Connect middleware, that provides many more helpers and structural aspects to build our web applications.
To get started with the Express framework, we need to install it using npm, the Node.js package manager.
sudo npm install -g express
The previous command will install Express as a global (-g
) module and make express
available as a command. Let us create an Express app:
express hello-express
This will create a folder called hello-express
with certain files and folders in it. Let us see and understand these files.
The first file to understand is package.json
. This is the file that defines a Node.js application package. It has the application metadata such as the name, description, and version. More importantly, it has the module dependencies listed. The dependency list is used by npm to download the required modules.
{ "name": "application-name", "version": "0.0.1", "private": true, "scripts": { "start": "node app" }, "dependencies": { "express": "3.1.0", "jade": "*" } }
The most important things in your package.json
are the name
and version
fields. These fields are required, and together, they form a unique identifier for a particular release of the package. To begin with, let us change the name of our package to hello-express
. The version
field
consists of the following (in the same order):
If we set private
to true, npm will not publish it to a repository. This ensures that you don't end up publishing your code to a public repository by mistake.
The scripts
object has a mapping of commands to those points in the application lifecycle at which they should be run. In this package, we are telling Node.js that it should run the node app
command when the application is started with npm. There are some predefined lifecycle commands, such as start
, stop
, restart
, and test
, which can be run using npm <command>
like npm start
.
You can also run arbitrary commands using run-script
. For this, you add the command to the scripts
object and then run it as npm run-script <command>
.
And finally—the most interesting part of the package that brings in the magic—dependencies
. This object is a mapping of the name and version of your dependency packages and will be used by npm to pull in all the required dependencies.
In our package, express
has already defined the dependency on Express and Jade. To pull in these dependencies, run the following command:
npm install
The output will list all the dependencies it downloaded.
[email protected] node_modules/jade
[email protected] node_modules/express
├── [email protected] ([email protected])
└── [email protected] ([email protected], [email protected], [email protected], [email protected])
The dependencies will be placed in
a folder called node_modules
.
Next, we will take a look at the application file app.js
:
var express = require('express') , routes = require('./routes') , 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); http.createServer(app).listen(app.get('port'), function(){ console.log("Express server listening on port " + app.get('port')); });
In the first few lines, Node.js loads
the modules required for us to work with. We are already familiar with http
and path
. The express
module brings in the Express framework. And one more module that we are loading in is ./routes
, which will load the module defined in the local routes
folder, defined by ./routes/index.js
. The following code snippet focuses on the first few lines of the previous code snippet:
var express = require('express') , routes = require('./routes') , http = require('http') , path = require('path'),
In the next line, it instantiates the Express framework as an app:
var app = express();
Then comes the application configuration:
app.configure(function(){ });
In the previous few lines, we are defining a function that will configure the app. The signature for app.configure
is app.configure([env], callback)
, where env
is the runtime environment variable or the production environment variable, as is defined by process.env.NODE_ENV
. When we don't specify env
, it will be set for all environments.
The following settings have been provided to alter how Express behaves:
env
: Environment mode, defaults to process.env.NODE_ENV
or "development"trust proxy
: Enables reverse proxy support, disabled by defaultjsonp callback
: Enables JSONP callback support, enabled by defaultjsonp callback name
: Changes the default callback name of ?callback=
json replacer
: JSON replacer callback, null
by defaultjson spaces
: JSON response spaces for formatting; defaults to 2
in development, 0
in productioncase sensitive routing
: Enables case sensitivity, disabled by default, treating /Foo
and /foo
as the samestrict routing
: Enables strict routing, by default /foo
and /foo/
are treated the same by the routerview cache
: Enables view template compilation caching, enabled in production by defaultview engine
: The default engine extension to use when omittedviews
: The view directory pathThe following code snippet demonstrates how to assign settings to an application:
app.set('port', process.env.PORT || 3000); app.set('views', __dirname + '/views'), app.set('view engine', 'jade'),
The settings used by the application here are port
, views
, and view engine
, specifying that the application should run on port 3000
, the views will be placed in the views
folder, and the engine to be used is Jade. We will see more about views later. Certain features can also be specified, as shown in the following snippet:
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')));
As Express builds over Connect middleware, it brings in a lot of existing functionality from Connect. Connect's use
method configures the app to utilize the given middleware handle for the given route, where the route defaults to /
. You can see the list of middleware provided by Connect at http://www.senchalabs.org/connect/.
Let us walk through the middleware components being used here. The Favicon middleware will serve the favicon for the application. The Logger middleware logs requests in a custom format.
The Body parser parses the request bodies supporting different formats; this includes application/json
, application/x-www-form-urlencoded
, and multipart/form-data
.
Method Override enables the faux HTTP method support. This means that if we would like to stimulate the DELETE
and PUT
method calls to our application, we can do it by adding a _method
parameter to the request.
app.router
provides an enhanced version of Connect's router
module. Basically, this is the component that determines what to do when we use routing methods like app.get
. The last middleware, Static, provides a static file server and configures it, serving files from the public
directory.
For the development environment, the following two lines of code show how to set up the Error handler middleware so as to provide stack traces and error messages in the responses.
app.configure('development', function(){ app.use(express.errorHandler()); });
The next line configures the router to route /
to be handled by the index
method in the routes
module:
app.get('/', routes.index);
At the end, we start the HTTP server configured to use the app instance that we just configured.
http.createServer(app).listen(app.get('port'), function(){ console.log("Express server listening on port " + app.get('port')); });
In the configuration of the app, we saw some folders coming into play, namely, routes
, views
, and public
.
routes
is a module that we will be writing all our handlers to. In the case of /
, we have mapped it to serve from the index method, using the routes.index
method. If you open routes/index.js
, you will see that index
is a method exposed from this module.
exports.index = function(req, res){ res.render('index', { title: 'Express' }); };
This function signature is similar to the handlers we wrote. It is a function that takes a request and response as parameters. Here we are using the Express method response.render
, which will render the mentioned view using the second parameter as the model or data.
The views are present in the views
folder and use the Jade (http://jade-lang.com/) view engine. Jade is a high-performance template engine, heavily influencedby Haml (http://haml.info/), and implemented with JavaScript for Node.js. Like many modern HTML generation engines, Jade tries to make the UI code easier, cleaner, and simpler, getting rid of the inline code and the HTML tags noise.
We will now see the views defined in our Express app. There are two files to see here: layout.jade
and index.jade
.
layout.jade
, as the name suggests, is the template for the layout that will be used by the different pages in our application. It may be used to place the common code of the skeleton for the pages in our
application, which is shown in the following snippet:
doctype 5 html head title= title link(rel='stylesheet', href='/stylesheets/style.css') body block content
In Jade, we don't need the start
and end
tags because it identifies the start and end of the tags by the indented blocks. So when we render this Jade file, it will generate the following HTML code:
<!DOCTYPE html> <html> <head> <title>{TITLE}</title> <link rel="stylesheet" href="/stylesheets/style.css" /> </head> <body>{CONTENT}</body> </html>
In the previous piece of code, two things are left undefined, {TITLE}
and {CONTENT}
. In the Jade template, we define the title as follows:
title= title
We tell Jade to use the title from the data passed to render
as title
. The second thing, {CONTENT}
, is defined as block in Jade.
block content
block content
is a plugin point provided in the layout template, which can be described by any template extending from it.
index.jade
inherits from layout.jade
. In our index handler, we render the index view using the data {title: 'Express'}
. Take a look at the following code snippet:
extends layout block content h1= title p Welcome to #{title}
In the previous file, we define the content block to have a h1
and p
tags. So, with the given input and because it extends
the layout, the Jade engine will generate the following HTML:
<!DOCTYPE html> <html> <head> <title>Express</title> <link rel="stylesheet" href="/stylesheets/style.css" /> </head> <body> <h1>Express</h1> <p>Welcome to Express</p> </body> </html>
We will see more functionality and syntax in Jade as we work on our chat application in the next chapter.
In the HTML code generated, we can see that /stylesheets/style.css
is being referred to; this file is served by the static file server we configured in the app. We can find this and the other files in the public folder.
To run this application, we will use npm. Run the following command on the console:
npm start
Then go to http://localhost:3000/
.