Middleware is a function which is called before the route handler. Middleware functions have access to the request and response objects, and the
next() middleware function in the application’s request-response cycle. The next middleware function is commonly denoted by a variable named
Nest middleware are, by default, equivalent to express middleware. The following description from the official express documentation describes the capabilities of middleware:
Middleware functions can perform the following tasks:
- execute any code.
- make changes to the request and the response objects.
- end the request-response cycle.
- call the next middleware function in the stack.
- if the current middleware function does not end the request-response cycle, it must call
next()to pass control to the next middleware function. Otherwise, the request will be left hanging.
You implement custom Nest middleware in either a function, or in a class with an
@Injectable() decorator. The class should implement the
NestMiddleware interface, while the function does not have any special requirements. Let's start by implementing a simple middleware feature using the class method.
Nest middleware fully supports Dependency Injection. Just as with providers and controllers, they are able to inject dependencies that are available within the same module. As usual, this is done through the
There is no place for middleware in the
@Module() decorator. Instead, we set them up using the
configure() method of the module class. Modules that include middleware have to implement the
NestModule interface. Let's set up the
LoggerMiddleware at the
In the above example we have set up the
LoggerMiddleware for the
/cats route handlers that were previously defined inside the
CatsController. We may also further restrict a middleware to a particular request method by passing an object containing the route
path and request
method to the
forRoutes() method when configuring the middleware. In the example below, notice that we import the
RequestMethod enum to reference the desired request method type.
info Hint The
configure()method can be made asynchronous using
async/await(e.g., you can
awaitcompletion of an asynchronous operation inside the
Pattern based routes are supported as well. For instance, the asterisk is used as a wildcard, and will match any combination of characters:
'ab*cd' route path will match
abecd, and so on. The characters
() may be used in a route path, and are subsets of their regular expression counterparts. The hyphen (
-) and the dot (
.) are interpreted literally by string-based paths.
warning Warning The
fastifypackage uses the latest version of the
path-to-regexppackage, which no longer supports wildcard asterisks
*. Instead, you must use parameters (e.g.,
MiddlewareConsumer is a helper class. It provides several built-in methods to manage middleware. All of them can be simply chained in the fluent style. The
forRoutes() method can take a single string, multiple strings, a
RouteInfo object, a controller class and even multiple controller classes. In most cases you'll probably just pass a list of controllers separated by commas. Below is an example with a single controller:
info Hint The
apply()method may either take a single middleware, or multiple arguments to specify multiple middlewares.
At times we want to exclude certain routes from having the middleware applied. We can easily exclude certain routes with the
exclude() method. This method can take a single string, multiple strings, or a
RouteInfo object identifying routes to be excluded, as shown below:
info Hint The
exclude()method supports wildcard parameters using the path-to-regexp package.
With the example above,
LoggerMiddleware will be bound to all routes defined inside
CatsController except the three passed to the
LoggerMiddleware class we've been using is quite simple. It has no members, no additional methods, and no dependencies. Why can't we just define it in a simple function instead of a class? In fact, we can. This type of middleware is called functional middleware. Let's transform the logger middleware from class-based into functional middleware to illustrate the difference:
And use it within the
info Hint Consider using the simpler functional middleware alternative any time your middleware doesn't need any dependencies.
As mentioned above, in order to bind multiple middleware that are executed sequentially, simply provide a comma separated list inside the
If we want to bind middleware to every registered route at once, we can use the
use() method that is supplied by the