Express is a framework for Node.js that brings lots of features for building web and mobile applications.
In this post, I will be talking about some important things I have learned about using Express relating to Routing and Middleware. I won't be going over the basic's such as creating a server with express and listening for requests sent to that server.
What is Middleware?
Let's imagine a game you may have heard (or played) as a kid - Monkey in the middle. Let's see this game being played as a bystander.
On one side of the game there is a person (client), and on the other end is another person (server). They are tossing a ball to each other in the air back and forth. This ball will act as a request and the response depending on who threw the ball.
Now let's add a "middle-man" to the equation. This person (middleware) will be catching the ball in the middle and passing it to the other person behind them. (Instead of the people trying to toss it over the middle person's head, they purposefully pass it to them). This person in the middle is what a middleware is.
A middleware is a function that runs in between requests and responses which may process, modify, or control the request/response object.
We can create middleware by defining a function:
const middlewareFunc = (req, res, next) => {
// do some work
next(); // have the request/response continue down the chain
}
We call next()
at the end of each middleware so the request/response can continue to the client/server.
To have the middleware run, we need to also include it to the express server:
// This should be defined before the routes are defined
app.use(middlewareFunc);
Three kinds of middleware
1) Application-level Middleware
2) Router-level Middleware
3) Error-handling Middleware
Application-level Middleware
Application-level Middleware is a function that will run for every route you define. For example, vising /
and /users
will have this function run:
// Request data will be logged to the console
const logRequest = (req, res, next) => {
console.log(`[${req.method}]: ${req.url}`);
next();
}
Router-level Middleware
You can specify middleware to run on specific routes instead of the entire app. To do so, you add the middleware function name to the request method.
// Define a middleware to run
const middlewareFunc = (req, res, next) => {}
// Add the middleware to the request method
app.get('/', middlewareFunc, (req, res) => {
// middleware will run on only this GET route
});
Error-handling Middleware
This kind of middleware is special in that there is an error with the request / response, it will run the middleware.
Important: If you declare a error-handling middleware, you will need to have
app.use(middlewareFunc)
after the routes have been specified.
It also has a new parameter in the function as well, err
:
const errorHandler = (err, req, res, next) => {
console.error(err.stack);
res.status(err.status || 500).json({
error: {
message: err.message || 'An unexpected error has occurred'
}
});
}
Now whenever we provide in our route with next(error)
, it will run this middleware:
Note that this route also has the
next
parameter.
app.get('/items/:id', (req, res, next) => {
try {
const itemId = Number(req.params.id);
const item = items.find((i) => i.id === itemId);
if (!itemId) {
const error = new Error('Item not found');
error.status = 404;
return next(error)
}
res.json(item);
} catch (error) {
next(error);
}
});
You should ask yourself these questions to determine if a next
parameter should be added to your route:
- Could this route fail because of external / internal issues?
- Is the required data being validated?
- Is the route restricted to others?
- Does the route involve multiple steps that could fail?
- Is there error-handling middleware in place?
HTTP Methods Cheatsheet
I am providing this cheatsheet here to showcase when to access the request body or params.
Don't forget to include the built-in middleware for parsing json (
app.use(express.json())
) for POST and PUT methods if the data is in json!
[GET] /items/:id
const {id} = req.params.id
[POST] /items
const data = req.body
[PUT] /items/:id
const {id, name} = req.body
[DELETE] /items/:id
const id = Number(req.params.id)
Top comments (0)