Express Yourself Deux
Intro to the ExpressJS Web Application Framework
What is a Framework?
Per dictionary.com a framework is defined as :
an essential supporting structure of a building, vehicle, or object.
a basic structure underlying a system, concept, or text.
What is a Web Application Framework?
Therefore we can define a web application framework as :
A basic structure (or underlying pre-existing code) that supports the commonalities of the necessary components that make up a web application
This includes things like:
- Http/Https
- Routing
- Sessions
- Cookies
- Templating
- and more...
What is ExpressJS?
Express is a minimalist, un-opinionated web application framework written in NodeJS for building web applications.
It gives us the ability to get a web application up and running quickly and supports basic concepts related to the web without enforcing too much structure or adding too many features that may not be used in every application.
It is very good at allowing us to handle the different types of HTTP requests and setting up the routes for our application with the ability to be easily extended via NPM packages for other features like cookies, sessions, form inputs, etc...
Installation
//Create the project directory
$ mkdir myapp
$ cd myapp
//Initialize the application
$ npm init
entry point: (index.js) -> Change to app.js
//Install Express - it is a NPM module like anything else
$ npm install express --save
//Create our app.js entry point as defined in package.json
$ touch app.js
First we create a new NPM project and install the Express NPM module
Create our App
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.send('Hello World!');
});
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
Next we add a few basic constructs to create our web application
And to run your application:
#Using node
$ node app.js
#Using nodemon
$ nodemon app.js
Try it out: http://localhost:3000
Adding more routes
var express = require('express');
var app = express();
app.get('/', function (req, res) {
res.send('Hello World!');
});
app.get('/about', function(req, res) {
res.send('We are awesome!');
}
app.get('/faq', function(req, res) {
res.send('What you need?');
}
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
We can easily add more routes by adding more "route handlers" where the method is the HTTP method of the request:
Adding moooore routes
// respond with contact form on the contact page
app.get('/contact', function (req, res) {
res.send('...<form>....'); //Example shorthand text for HTML form
});
// accept POST request on the contact page
app.post('/contact', function (req, res) {
res.send('Got a POST request');
});
// accept PUT request at /user
app.put('/user', function (req, res) {
res.send('Got a PUT request at /user');
});
// accept DELETE request at /user
app.delete('/user', function (req, res) {
res.send('Got a DELETE request at /user');
});
Like we said the method reflects the HTTP verb of the type of request our application has received so we can easily handle any type of request:
Serving static files
// respond with contact form on the contact page
app.use(express.static('public'));
Our application will also serve images, JavaScript and CSS files. We don't need Node to "process" these requests so we tell Express to "use" a static directory that we define as the location to look for these requests.
Express is smart enough to know what kind of requests are static files and to look here first for those requests.
This saves your server processing cycles for not having to handle these requests by cycling through lines of code or writing a route handler for every file imagineable.
Our basic app
var express = require('express');
var app = express();
app.use(express.static('public'));
app.get('/', function (req, res) {
res.send('Hello World!');
});
app.get('/contact', function (req, res) {
res.send('...<form>....'); //Example shorthand text for HTML form
});
app.post('/contact', function (req, res) {
res.send('Got a POST request');
});
app.put('/user', function (req, res) {
res.send('Got a PUT request at /user');
});
app.delete('/user', function (req, res) {
res.send('Got a DELETE request at /user');
});
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
Routing +
Advanced Route Handling
If we have multiple HTTP methods for a single route we can use app.route and chain our methods for handling a single URL path for multiple types of requests
app.route('/book')
.get(function(req, res) {
res.send('Get a random book');
})
.post(function(req, res) {
res.send('Add a book');
})
.put(function(req, res) {
res.send('Update the book');
});
Routing +
Advanced Route Matching
We can also use RegEx for matching patterns of routes to all be handled by a single route handler
// will match acd and abcd
app.get('/ab?cd', function(req, res) {
res.send('ab?cd');
});
// will match abcd, abbcd, abbbcd, and so on
app.get('/ab+cd', function(req, res) {
res.send('ab+cd');
});
// will match abcd, abxcd, abRABDOMcd, ab123cd, and so on
app.get('/ab*cd', function(req, res) {
res.send('ab*cd');
});
// will match /abe and /abcde
app.get('/ab(cd)?e', function(req, res) {
res.send('ab(cd)?e');
});
Routing +
We don't really want to pollute our main app.js file with a ton of routes so it's best practice to create modules that export our routes for larger applications
Route File Structure
//File path: {{project_directory}}/routes/users.js
var express = require('express');
var router = express.Router();
//GET http://localhost:3000/users
router.get('/', function(req, res) {
res.send('All users');
});
//GET http://localhost:3000/users/1
router.get('/:id', function(req, res) {
res.send('Some dude');
});
//POST http://localhost:3000/users
router.post('/', function(req, res) {
res.send('Creating a dude');
}
//PUT http://localhost:3000/users/1
router.put('/:id', function(req, res) {
res.send('Updated a dude');
}
module.exports = router;
var users = require('./routes/users');
.
.
.
//Defer all routes matching
//http://localhost:3000/users to module
app.use('/users', users);
.
.
.
Responses
Every HTTP request is designed to return an HTTP response and Express gives us methods to send multiple types of responses:
res.download() | Prompt a file to be downloaded. |
res.end() | End the response process. |
res.json() | Send a JSON response. |
res.jsonp() | Send a JSON response with JSONP support. |
res.redirect() | Redirect a request. |
res.render() | Render a view template. |
res.send() | Send a response of various types. |
res.sendFile | Send a file as an octet stream. |
res.sendStatus() | Set the response status code and send its string representation as the response body. |
Templating
Obviously we don't just send text to the client, we usually send back HTML in standard web applications and deal with dynamic data in our applications as well.
Template engines offer us the ability to bind static HTML to dynamic data and output the result of the two as our HTML responses to serve our HTTP requests.
There are many template engines available:
- Jade
- Handlebars
- Dust
- EJS
- more...
Template Engines
"Template engines offer us the ability to bind static HTML to dynamic data and output the result of the two as our HTML responses to serve our HTTP requests."
All template engines have the same purpose of allowing us to pass data to our template engine to dynamically render static output
The main difference between them is more or less syntax of how we write our templates.
In Express, regardless of the template engine used the syntax to call them is the same using the res.render() function.
res.render()
As noted before, the res object is the object we use to send an HTTP response back to the client based on the HTTP request our application received.
//When we call the render() function we pass it an object of data values to bind to output
app.get('/', function (req, res) {
res.render('index', { userName: 'Jason', email: 'jaywon@dark.net'});
});
Which would be passed to a template like:
//index.jade
h1
Hello #{username}
div
Your email is: #{email}
//index.hbs
<h1>
Hello {{username}}
</h1>
<div>
Your email is: {{email}}
</div>
Jade (.jade)
Handlebars (.hbs)
Both templates would render the exact same HTML output
Adding Template Engine
To tell Express which template engine we will be using we need to:
- Install the NPM template module
- Require it in our app.js (or main server file)
- Tell Express the template engine we will use
- Tell Express where our template files are located
$ npm install --save jade
//Tell Express which Template engine we are using by NPM module name
app.set('view engine', 'jade');
//Tell Express where our template files live
app.set('views', './views');
NOTE: Express will automatically append the file extension when using res.render() but needs to know where to look.
Things to know:
app.locals - Used for defining application level variables that are accessible anywhere in your application
Express has gone through major revisions between version 3.x and 4.x. When looking at documentation make sure it is referencing the proper version you are using.
Even though we don't handle HTTP headers manually as we did previously, they are still accessible on the req object. Take a look at the docs for the Request/Response objects to see what properties are available.
Resources
Copy of Express Yourself Deux
By Ray Farias
Copy of Express Yourself Deux
- 1,573