3.1: Express.js
Learning Objectives
Revise the HTTP Request and Reponse Cycle.
Express.js is a server application framework that helps us receive requests from clients and respond with data
Understand how to create routes and corresponding middleware functions that handle requests to those routes
Know how to parse URL path and query parameters in route middleware
Middleware functions are functions that run during the "request-response cycle" and have access to Express request and response objects
HTTP Revision
Introduction
Express.js is a server application framework that helps us receive requests from clients and respond with data. Servers are computers without a screen that perform logic on behalf of clients such as storing and retrieving data.
Basic Express App
The following code is a minimal Express app that hosts a server at port 3000 and responds with "Hello, World!" at the root route, i.e. localhost:3000
when run locally or mysite.com
when deployed to mysite.com
. Check it out on StackBlitz, a popular online IDE!
Let's break down the above code.
Requiring
express
imports the Express library for us to initialise, configure and run our serverPORT
defines the port that our Express server will listen on. Recall from Module 2 that ports determine which applications receive which requests on servers. We use SCREAM_CASE to define constant variables likePORT
at the top of our files or in a separate constants file for easy access.const app = express()
initialises our Express applicationapp.get
is a route middleware (more on this below) that routes requests to a specific URL path to a specific middleware function to handle that requestres.send
is a method of the Express Response object that sends a response to the requesting clientapp.listen
tells the Express app to start listening for requests at the specified port and execute the specified callback function after successfully starting
In the following sections we will dig deeper into route middleware and middleware functions in general.
Fruit Express App (Simple)
Please checkout the finished code in this repository, ensure that you're on the simple_express
branch if you want to test out the application on your machine you will need to install the dependencies with the command npm install
after the installation you can then run the application with the command node index.js
Routes
Routes (aka "route middleware", "routing methods") are middleware functions that define how servers handle requests to specific URL paths with specific URL methods. Routes provide some of the most basic infrastructure for server applications. Read Express' official introduction to routes for context.
In the above example, our route middleware defines how our server responds to GET requests to the root route /
. Express applications typically have many routes that serve requests with various HTTP methods to many URL paths. We can handle other request methods by changing .get
to .post
, .put
or .delete
, and we can handle requests to other paths by changing the path parameter that is currently '/'
. We can change how our server responds to specific requests by changing logic in the middleware function, for example to query a database and return results. More on databases in coming submodules.
Read Express' official routing guide for a full introduction to Express routes, including how to use the express.Router
class to decompose our routes into router modules for clearer organisation and abstraction.
Require vs Import Statements
You may notice that Express docs use require
syntax to import modules. This is an older import syntax that is still supported by Node.js. Luckily we can generally use require
and import
statements interchangeably.
Require (aka CommonJS) syntax:
Import (aka ES Modules) syntax:
Express Request Extras
Please checkout the finished code in this repository, ensure that you're on the simple_express_params
branch if you want to test out the application on your machine you will need to install the dependencies with the command npm install
after the installation you can then run the application with the command node index.js
Express Fruit Application
Please checkout the finished code in this repository, ensure that you're on the crud_handlers
branch if you want to test out the application on your machine you will need to install the dependencies with the command npm install
after the installation you can then run the application with the command node index.js
Middleware
Middleware functions (aka "middleware") are functions that run during the "request-response cycle" and have access to Express request and response objects. The request-response cycle is the logic a server executes between when the server receives a request and when the server sends a response for that request. Routing methods of the format app.<METHOD>
are 1 form of middleware.
We can run other non-routing middleware in the request-response cycle by attaching middleware functions with app.use
before routing middleware. This will allow us to execute arbitrary logic using req
and res
objects before our routes, such as logging requests, adding metadata to our requests or validating authentication. Express executes middleware in the order the middleware is bound to the app
object, until any middleware sends a response back to the client.c
Notice in the above code we attach non-route middleware above route middleware because route middleware typically terminates the request-response cycle by calling response methods like res.send
.
Also notice how myLogger
calls next()
at the end of its execution to trigger the next middleware. Without calling next()
the client would never receive a response because Express would not call the subsequent middleware function.
Read Express' official guide to writing middleware for details.
Read Express' official guide to using middleware for details on how to use middleware in Express apps, including how to apply middleware on Express routers and how to apply imported 3rd-party middleware, which we will do often.
Express In-Built Middleware
Please checkout the finished code in this repository, ensure that you're on the built_in_middleware
branch if you want to test out the application on your machine you will need to install the dependencies with the command npm install
after the installation you can then run the application with the command node index.js
CORS
CORS (Cross-Origin Resource Sharing) is a security mechanism that allows servers to specify which domains other than their own to accept requests from. Without CORS, hackers at malicious websites could induce users to perform sensitive actions to manipulate legitimate backends using authentication information stored in the browser. With CORS, legitimate backends can prevent such attacks by only allowing requests from legitimate domains.
CORS is relevant for us now because we will host our frontends and backends on different domains, and we will need to configure our backends to allow requests from our frontends. Express provides an official CORS middleware NPM library cors
to configure CORS for our backends.
For now we will use the most open and least secure cors
configuration (app.use(cors());
) to get our apps working. There are many ways to configure Express' cors
library to be most secure that we can learn about later.
Express Structure
If you find that your backend index.js is getting rather long due to the amount of route handlers, middleware or other code that is implemented. We suggest that you apply some backend structure to your Express directories.
Please checkout the finished code in this repository, ensure that you're on the router_and_controller
branch if you want to test out the application on your machine you will need to install the dependencies with the command npm install
after the installation you can then run the application with the command node index.js
Does the class based code look unfamiliar have a look at the Rocket curriculum to touch up your understanding.
Additional Resources
Web Dev Simplified's intro to Express provides a video tutorial to the above Express concepts
Stackoverflow shares API server route design best practices
Portswigger provides a detailed explanation of CORS
Last updated