Chapter 11: Transactions on the Web
11.2 A More Capable Web Server: Express.js
Node.js by itself is a very simple web server, as seen previously. But with the addition of an extensive framework of objects, properties, and methods, such as that provided by the Express package, Node becomes a full-fledged Web server that can be used for just about any application.
Documentation:
Installing Express.js
The Express Framework
Moving an Existing Web Site into Express
Installing Express.js
Express has its own ideas about the best way to structure your Web site, so it’s best to start with a fresh folder, install Express, copy your pages into it, and then modify them to make use of Express.
To install Express:
- In the command-line interpreter, change directory (folder) to where your new Web site folder will be located.
To create the Express site framework we can use the Express Generator, a tool that is installed separately from Express. Ideally you will install it “globally” since it’s not actually part of your Web site:
Windows:
Type this command in the Node.js command prompt:
npm install express-generator -g
The files will be installed in your personal applications folder,
AppData\Roaming
, where it can be simply referenced.Macintosh:
If possible use administrator privileges to install Express Generator. Type this command in the Terminal:
sudo npm install express-generator -g
and when prompted type in your password. The files will be installed in the usual location for nonstandard applications,
/usr/local/bin
.If you don’t have administrator privileges you can run these commands instead:
export NPM_CONFIG_PREFIX=~/Applications/node_modules echo "export NPM_CONFIG_PREFIX=$NPM_CONFIG_PREFIX" >> ~/.bash_profile mkdir $NPM_CONFIG_PREFIX npm install -g express-generator
Note that this will only work with the Mac’s default command-line interpreter,
bash
. If you are using a different shell then you can probably also figure out how to adjust the above commands.
Now run the Express Generator with the name of the new Web site folder, e.g. by typing:
express -e gnex
This will create the folder (e.g.
gnex
) and install into it Express’ default structure, consisting of a number of files and folders that will be described shortly. With the-e
option, it will also add a requirement to use the EJS template engine, also to be described shortly.- One of the installed files is
package.json
, which provides configuration information for NPM, in particular about the different modules that the Web site depends on, such as Express itself:
To install these dependent modules, change directory into the Web site folder, e.g.{ "name": "gnex", "version": "0.0.0", "private": true, "scripts": { "start": "node ./bin/www" }, "dependencies": { "body-parser": "~1.13.2", "cookie-parser": "~1.3.5", "debug": "~2.2.0", "ejs": "~2.3.3", "express": "~4.13.1", "morgan": "~1.6.1", "serve-favicon": "~2.3.0" } }
and type the commandcd gnex
The dependent modules will be placed in the subfoldernpm install
node_modules
.
Your Web site is now ready! The configuration file package.json
also includes a script that you can use to easily start the server using NPM; again from the Web site folder, type the command:
npm start
⇒
> [email protected] start gnex
> node ./bin/www
To view the site, use your Web browser with the address http://localhost:3000
:
Express
Welcome to Express
To stop the server, return to the command-line interpreter and type control-C (hold down the key control or ctrl and press C).
The Express Framework
Express’ default structure consists of these files and folders:
app.js
— the main applicationbin
— a folder for other applications that you might wish to include, but also including the starting scriptwww
.node_modules
— a folder containing your application’s specific modulespackage.json
— a configuration filepublic
— a folder of static files such as images, scripts, and stylesheetsroutes
— a folder of JavaScripts that set up handling for particular locations on your Web siteviews
— a folder containing your Web pages
Express works as follows:
- The Web server is started with the script
bin/www
, which callsapp.js
, uses it to create a server, and starts the server; app
sets up:- The main document directory, e.g.
views
; - The connection between document paths or routes (e.g.
http://localhost:3000/index
) and the scripts or routers that respond to requests for them (e.g.routes/index.js
); - The view engine that processes document templates;
- The main document directory, e.g.
- The routers respond to requests for particular document routes, process the template documents, and send the result to the browser that requested the document.
Starting the Server
The initial script, bin/www
, has similarities to the previous simple server:
var app = require('../app');
var http = require('http');
var port = 3000;
app.set('port', port);
var server = http.createServer(app);
server.listen(port);
server.on('error', onError);
function onError(error) { .... }
Node’s require()
function is used to first load the main application module app.js
from the parent directory, followed by the http server module.
The object app
sets a port
property, a server is created using app
, and then the server method listen
is launched on this port.
The script concludes by setting an event listener that handles any errors that occur.
Server Setup
The main Express activity is set up in app.js
, which begins by loading the dependent modules specified in the package.json
file, and then creates the object app
as an instance of the express
module:
var express = require('express');
var app = express();
Your Web pages are stored in the folder views
, as specified by the property views
:
var path = require('path');
app.set('views', path.join(__dirname, 'views'));
The variable __dirname
is set by Node to the folder of the current script, and path.join()
produces a general reference to the folder views
, e.g. C:\...\gnex\views
on Windows and /.../gnex/views
on Mac.
How the Server Responds to Document Requests
The basic server responsibility of responding to requests for documents is implemented by Express’ .use()
method, which assigns particular router scripts to handle requests for particular document routes. For the default document at the server root, e.g. a request for http://localhost:3000/
, the assignment is:
var routes = require('./routes/index');
app.use('/', routes);
The object routes
is loaded from the script ./routes/index.js
, and it will be run whenever a request comes in for a path beginning with /
:
var router = express.Router();
/* GET home page. */
router.get('/', function(request, response, next) {
response.render('index', { title: 'Express' });
});
The method router.get('/', callback)
handles HTTP GET requests for the document /
and passes them to its callback function for processing. The result is sent back to the Web browser.
Additional documents below the root folder /
could also be listed in this module, e.g. router.get('/about', anothercallback)
.
Warning: the “root” folder for each router is the one assigned to it by app.use()
, i.e. the statement app.use('/users', require('./routes/users'))
will designate the route '/users'
as '/'
and '/users/local'
as '/local'
within users.js
.
How the Server Processes Document Templates
The object response
that is handed to these callback functions includes the method response.render()
, which is used to process or render document templates. It looks for its first argument in the folder views
, and then passes it through a view engine that was set earlier by app.js
:
app.set('view engine', 'ejs');
Express’ default view engine is called Jade, but we chose another one when we created the framework with the command express -e
, Enhanced JavaScript Templates (EJS), which is more understandable for most people.
The idea behind templates is that they allow you to set up a general structure for your pages, and then substitute in parameters that might vary from page to page. So in the default example above, the parameter title
is set to the string 'Express'
, and that is inserted into the page that is being rendered, views/index.ejs
, wherever the expression <%= title %>
appears:
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<h1><%= title %></h1>
<p>Welcome to <%= title %></p>
</body>
</html>
The result is then sent to the browser that requested the document:
Express
Welcome to Express
EJS has a number of options for substitution, some of use which we’ll see later. Check its documentation for a complete description.
Moving an Existing Web Site into Express
An existing Web site can be moved into Express without too much trouble:
- Copy all HTML files into the
views
folder, maintaining the same hierarchy; - Change their .html endings to .ejs if you want to be able to subsitute values into them, e.g. from a user form or database;
- For each HTML file:
- Add a route in
app.js
, e.g. forabout.ejs
, addvar about = require('./routes/about'); app.use('/', about);
- Add a corresponding file in the folder
routes
, e.g.about.js
:var express = require('express'); var router = express.Router(); /* GET home page. */ router.get('/about', function(request, response, next) { response.render('about', { someEJSvariable: 'value' }); });
- Add a route in
Copy your static files into
public
:- CSS files into
public/stylesheets
; you can change the latter name to the current folder name if different, e.g.public/css
; - JavaScript files into
public/javascripts
; you can change the latter name to the current folder name if different, e.g.public/js
; - Image files into
public/images
; you can change the latter name to your current folder name if different, e.g.public/img
.
Your references should not include
public
but should begin with a root folder reference/
, e.g.<link href="/css/styles.css">
will match the filepublic/css/styles.css
.- CSS files into