Node and Express

August 29, 2017

This is a continuation of my effort to document my Node learning process. I am still going through this excellent Udemy course and building upon very basic incremental examples to understand how and why Node can do the stuff that it does. In a previous blog post I wrote about how to create Node servers from scratch. This time, I’ll go through a few examples that use Node with Express to set up an app.

What Is Express

Express is a framework to enhance Node and make Node easier to work with. The first example that I went through just created a very basic app using Express, which is shown below. I’ve commented nearly every single line of code in (maybe painful) detail just to really understand what’s happening at every stage. Important things to make note of:

  • Express is simply a library providing functions and methods to make dealing with Node easier.
  • Maybe the most important line is var app = express(); as this is where we are creating our Express app.
  • Maybe the second most important line is app.listen(port) as this is where the server is actually created.
  • Anything that follows app.use is middleware. Middleware is something that happens between receiving a request and sending a response.
  • Anything that follows app.get/post/otherHTTPverb is how we set up our app’s routes.

var express = require('express');
// Middleware to parse body of HTTP requests
var bodyParser = require('body-parser');
// Invokes function returned from require.
// Creates an Express application;
// express() returns Express object
var app = express();
// Sets port equal to either the environment
// PORT variable OR 3000 as default.
// Can set up environment variables on servers
// when deploying for production.
var port = process.env.PORT || 3000;
// Create parser for requests with
// Content-Type: x-www-form-urlencoded
var urlencodedParser = bodyParser.urlencoded({ extended: false });
// Create parser for requests with
// Content-Type: application/json
var jsonParser = bodyParser.json();
// Mounts specified middleware function(s) at specified path;
// app.use() takes following params:
// 1. path: string|RegExp | (string|RegExp)[]
// 2. ...handlers: RequestHandler[] (callback functions, can be series of functions
// separated by commas or array of functions)
// Middleware function is executed when the base of
// the requested path matches path param.
// express.static() is built-in express middleware
// to serve static files.
// express.static() takes following params:
// 1. root: string (dir from which static assets to be served)
// 2. options?: serveStatic.ServeStaticOptions
// Here we have a 'public' folder in root dir with a style.css file
app.use('/assets', express.static(__dirname + '/public'));
// Make your own middleware.
app.use('/', function(req, res, next){
console.log('Request Url: ' + req.url);
// Express provides next() for middleware to the
// function that you give as callback when route is matched.
// next() just means 'run the next middleware';
// Without next(), request will be left hanging.
next();
});
// Executes this function if a GET request
// is received to this url.
app.get('/', function(req, res) {
// Indicate body to be included in response.
// Don't need to indicate Content-type header.
// When browser sees href=assets/style.css it will
// generate an HTTP req for site/assets/style.css,
// and this will be handled by Node.
// When it sees /assets it will handle request in
// app.use('/assets' ...).
res.send('<html><head><link href=assets/style.css type=text/css rel=stylesheet /></head><body><h1>Donuts</h1></body></html>');
});
// Use res.sendFile to serve an html file
app.get('/form', function(req, res){
res.sendFile(__dirname + '/form.htm');
});
// :id indicates that id is a variable name.
// Access id using req.params.id.
// Can also access request query string using req.query.param,
// where param is name from a query string name value pair
// (ie url?param=4&name=value).
// Now we can access urls such as:
// /person/3
// /person/Jerry
app.get('/person/:id', function(req, res) {
res.send('<html><head></head><body><h1>Donuts for Person ' + req.params.id + '</h1></body></html>');
});
// Pass urlencodedParser (middleware we created earlier)
// to post statement as a callback.
// urlencodedParser is middleware that will be called
// before function(req, res) is called.
// urlencodedParser gives us access to req.body.param,
// where param is name of name value pair in body of request.
// So if '/person' is seen in the url, and it's of method post,
// then this middleware and callback will be run.
app.post('/person', urlencodedParser, function(req, res){
res.send('Thank you!');
console.log(req.body.firstname);
console.log(req.body.lastname);
});
// Pass jsonParser (middleware we created earlier)
// to post statement as a callback.
// jsonParser gives us access to req.body.param,
// where param is name in json object in body of request.
app.post('/personjson', jsonParser, function(req, res){
res.send('Thankyou for the json data');
console.log(req.body.firstname);
console.log(req.body.lastname);
});
// Send json data in response to GET from /api url
app.get('/api', function(req, res) {
res.json({ firstname: 'Jelly', lastname: 'Donut' });
});
// listen() calls http.createServer under the hood.
// listen() takes the following params:
// 1. port: number
// 2. hostname: string
// 3. backlog: number
// 4. callback?: Function
// returns a http.Server object.
// Here we specify port 3000.
app.listen(port);
view raw app.js hosted with ❤ by GitHub

<html>
<head>
<link href="assets/style.css" type="text/css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js" ></script>
</head>
<body>
<h1>Jelly Filled Donut</h1>
<form method="POST" action="/person">
First name: <input type="text" id="firstname" name="firstname" /> <br />
Last name: <input type="text" id="lastname"
name="lastname" /> <br />
<input type="submit" value="Submit" />
</form>
<script>
$.ajax({
type: "POST",
url: "/personjson",
data: JSON.stringify({ firstname: 'Reese', lastname: 'Donut' }),
dataType: 'json',
contentType: 'application/json'
});
</script>
</body>
</html>
view raw form.htm hosted with ❤ by GitHub

In this example, GET requests to the /form route will serve a static HTML file.

Structuring the App

The next example, we look at a different way of structuring our app to separate routes and make them easier to deal with. Here, we have a folder called controllers in the same directory as app.js and form.htm, and controllers contains apiController.js and htmlController.js. The static file form.htm stays the same and everything that has changed from the previous example is indicated by comments.

var express = require('express');
var app = express();
// Import the functions returned by apiController and htmlController
// to add endpoints/routes to app.
var apiController = require('./controllers/apiController');
var htmlController = require('./controllers/htmlController');
var port = process.env.PORT || 3000;
// Middleware
app.use('/assets', express.static(__dirname + '/public'));
app.use('/', function(req, res, next){
console.log('Request Url: ' + req.url);
next();
});
// Routes
// Can pass app around since it is an object (mutable/passed by ref).
// Pass our app to the function returned by
// apiController, which adds /api endpoints to app.
apiController(app);
// Same with html controller.
htmlController(app);
app.listen(port);
view raw app.js hosted with ❤ by GitHub

module.exports = function(app) {
// This contains all of the endpoints that return views/html.
// The function takes an app object and adds the endpoints
// to the app.
app.get('/', function(req, res) {
res.send('<html><head><link href=assets/style.css type=text/css rel=stylesheet /></head><body><h1>Donuts</h1></body></html>');
});
app.get('/form', function(req, res){
res.sendFile(__dirname + '/form.htm');
});
app.get('/person/:id', function(req, res) {
res.send('<html><head></head><body><h1>Donuts for Person ' + req.params.id + '</h1></body></html>');
});
app.post('/person', urlencodedParser, function(req, res){
res.send('Thank you!');
console.log(req.body.firstname);
console.log(req.body.lastname);
});
app.post('/personjson', jsonParser, function(req, res){
res.send('Thankyou for the json data');
console.log(req.body.firstname);
console.log(req.body.lastname);
});
}
view raw apiController.js hosted with ❤ by GitHub

var bodyParser = require('body-parser');
var urlencodedParser = bodyParser.urlencoded({ extended: false });
var jsonParser = bodyParser.json();
module.exports = function(app) {
// This contains all of the endpoints that return views/html.
// The function takes an app object and adds the endpoints
// to the app.
app.get('/', function(req, res) {
res.send('<html><head><link href=assets/style.css type=text/css rel=stylesheet /></head><body><h1>Donuts</h1></body></html>');
});
app.get('/form', function(req, res){
res.sendFile(__dirname + '/form.htm');
});
app.get('/person/:id', function(req, res) {
res.send('<html><head></head><body><h1>Donuts for Person ' + req.params.id + '</h1></body></html>');
});
app.post('/person', urlencodedParser, function(req, res){
res.send('Thank you!');
console.log(req.body.firstname);
console.log(req.body.lastname);
});
app.post('/personjson', jsonParser, function(req, res){
res.send('Thankyou for the json data');
console.log(req.body.firstname);
console.log(req.body.lastname);
});
}
view raw htmlController.js hosted with ❤ by GitHub

Using the Express Router

The next example deals with another way of structuring our app and uses the Router middleware provided by Express. Here, we have a folder called routes in the same directory as app.js, and routes contains index.js and users.js. Both of the routes files return an Express Router object, and then the main app.js file passes those Router objects to its own middleware. This effectively sets up routes with subroutes, where the routes defined in app.js are the main routes and the routes defined in the routes files are the subroutes that can be accessed via the main routes.

var express = require('express');
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
var port = process.env.PORT || 3000;
// path matching / will be handled by routes/index.js.
// index.js is set up with a '/something' subroute which can
// be accessed now with /something ,
// as well as a '/' subroute which can be accessed with '/'
app.use('/', routes);
// path matching /users/ will be handled by routes/users.js.
// Set a path '/users' and then within that path, the routes are processed.
// Basically, it takes path matching '/user/(whatever the matching routes are in users.js router)'.
// Paths defined in users.js router are the users/ subroutes.
// In this example, users is only set up with '/' path so
// it will respond to paths matching '/users/'
app.use('/users', users);
app.listen(port);
view raw app.js hosted with ❤ by GitHub

var express = require('express');
// Router middleware;
// put GETs/POSTs/etc on Router
var router = express.Router();
// GET /index/
router.get('/', function(req, res, next) {
res.send('Root');
});
// GET /index/something
router.get('/something', function(req, res, next) {
res.send('respond with something');
});
module.exports = router;
view raw index.js hosted with ❤ by GitHub

var express = require('express');
// Router middleware;
// put GETs/POSTs/etc on Router
var router = express.Router();
// GET /users/
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
module.exports = router;
view raw users.js hosted with ❤ by GitHub

These are all definitely just demonstrative examples that don’t do anything terribly exciting, but they helped me to understand how Express works with Node!