Introducing ExpressJS
Express is a web application framework for NodeJS. It is a highly configurable feature-rich framework which does not restrict the project structure basing on architecture. There are lot more required libraries, NodeFrameworks
The documentation of ExpressJS is highly informative. So, what I want to cover here is how to start off an express based application, understand the middlewares you are going to use.
Make sure that the Node and NPM are installed.
Installing Express globally will give you a generator automatically. But I will suggesting installing the express generator which gives you a express binary.
~$npm install -g express-generator
While generating the app you can configure it with following options (taken from above mentioned express guide)
Usage: express [options]
Options:
-h, --help output usage information
-V, --version output the version number
-e, --ejs add ejs engine support (defaults to jade)
-H, --hogan add hogan.js engine support
-c, --css add stylesheet support (less|stylus) (defaults to plain css)
-f, --force force on non-empty directory
You can create an express app by typing express and sending the name of the project as the parameter. Since we added no options it generated scaffold uses plain CSS and Jade templates.
~$express MyExpressApp
create : MyExpressApp
create : MyExpressApp/package.json
create : MyExpressApp/app.js
create : MyExpressApp/public
create : MyExpressApp/public/stylesheets
create : MyExpressApp/public/stylesheets/style.css
create : MyExpressApp/routes
create : MyExpressApp/routes/index.js
create : MyExpressApp/routes/user.js
create : MyExpressApp/public/javascripts
create : MyExpressApp/views
create : MyExpressApp/views/index.jade
create : MyExpressApp/views/layout.jade
create : MyExpressApp/views/error.jade
create : MyExpressApp/public/images
create : MyExpressApp/bin
create : MyExpressApp/bin/www
install dependencies:
$ cd MyExpressApp && npm install
run the app:
$ DEBUG=my-application ./bin/www
Now install the dependencies and start running the app
~$cd MyExpressApp
MyExpressApp-$npm install
MyExpressApp-$npm start
Go to browser and open http://localhost:3000
. There you are, you first Node Express Server is up and running. You may want to look at multiple express examples.
Dwelling into app
Lets the file app.js
which is the starting point of your server. Though, there are multiple configurations available in Express I will discuss only the important parts of it. You can read the rest from the Express guide.
After loading the importing the required node modules, get the instance of Express server from express()
we shall look at the following configurations
//Letting the express know where the views are available
app.set('views', path.join(__dirname, 'views'));
//Setting the view engine to jade
app.set('view engine', 'jade');
Middlewares
Lets look at the middlewares. Every app.use()
function call registers a new middleware. So, when a server receives new request first middleware is called and if the request can be answered the request will be answered else it will be forwarded to next middleware by invoking next()
, usually used to call the next listener
var favicon = require('static-favicon');
//Gets the webpage's fav-icon which is the first middleware
app.use(favicon());
// Logger, for logging the server requests
// Morgan is a logging library from ExpressJS
var logger = require('morgan');
app.use(logger('dev'));
Body Parsers
Body parsing middleware. Parsing the body of server requests which are in JSON format like the POST data will be handled by a middleware bodyParser.json()
. Similarly encoded url will be decoded by another middleware bodyParser.urlencoded()
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
Cookies
Parse Cookie header and populate req.cookies
with an object with cookie names as keys. So, in your controller to access the user cookies it is just about looking into req.cookies
var cookieParser = require('cookie-parser');
app.use(cookieParser());
Static Files
All the static files which should be publicly accessable can be served using express.static()
middleware. So every api request will go through this middleware and see if the requested path is on the given static path of this disk. So, there will be a lag of atleast 1ms for the server to respond over all. So one way of handling this can be via setting a prefix for accessing static files, check the following code snippet. All the public files need to be prefixed with /static
like http://localhost:3000/js/script.js to http://localhost:3000/static/js/script.js
app.use(express.static(path.join(__dirname, 'public')));
//Setting a prefix value
app.use('/static', express.static(path.join(__dirname, 'public')));
Refer SO Answer for more information on static files and its order compared to router
Router and Routes
Routing of the different web request to their respective controllers will be handled by the app.router
. If none of the above middlewares cannot address the user request then app.router
will check all the routes registered with it and if any route matches the request url then the respective callback will be called.
app.use(app.router);
// Place where u have your controllers
var routes = require('./routes');
var users = require('./routes/user');
// Registering the routes
app.get('/', routes.index);
app.get('/users', users.list);
If none of the above middlewares are not able handle the user request, it means the path user request is not found. So, our next middleware is trying to respond with Not Found or 404 response.
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
Error Handling
We can have a middleware which will always be available to handle the errors in the application. So this will be given in the end of all the middlewares. The arity of this middleware is 4 with signature function(err, req, res, next)
So, from any middleware above if there is an error you want to throw just call next(err)
. From the below snippet you will find 2 error middlewares one in the development mode to get the full error stack trace and other in the production to just display the error message.
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.render('error', {
message: err.message,
error: {}
});
});
As you see these are list of middlewares provided by Express but it is up to us, we can create new, delete the existing, replace with a better alternative. For Example, check flatiron for alternatives to these Express middlewares and you can use any of those middlewares replacing the ones provided by Express.