Middlewares
Middleware is a function which is called before the route handler method. Middleware functions have access to request
and response
objects, and next()
function which calls the next middleware or the route method in the applications' request response life cycle.
You can use middlewares to handle the following use cases
- execute some piece of code
- modify the request response life cycle.
- Pre-Validate the request headers, or on payload.
- Call the
next
middleware function in the stack, etc.
INFO
Middlewares are dumb in nature, which means they don't know which route handler will be called to handle the request. If you are looking to access the context of route handler, you can take a look at Guards.
Creating Middlewares
To create a middleware, let's create a file api-key-middleware.ts
inside the app/http/middlewares
directory, you will need to create a class like shown below inside the file we just created.
import { IntentMiddleware, Request, Response, MiddlewareNext } from '@intentjs/core';
export class ApiKeyMiddleware extends IntentMiddleware {
use(req: Request, res: Response, next: MiddlewareNext): void {
const payload = req.all();
// your code here.
next();
}
}
By default nature of the middleware is supposed to be synchronous, but if would like to make an asynchronous middleware then you don't need to call the next
method.
import { IntentMiddleware, Request, Response, MiddlewareNext } from '@intentjs/core';
export class ApiKeyMiddleware extends IntentMiddleware {
async use(req: Request, res: Response, next: MiddlewareNext): Promise<void> {
new Promise((resolve, reject) => {
// your code here
resolve(1);
})
}
}
We will write our logic inside the use
method, which will run whenever there is any request coming in.
Middlewares are fully compatible with our application containers and service providers, which means you can inject some dependencies inside the ApiKeyMiddleware
like below.
import { IntentMiddleware, Request, Response } from '@intentjs/core';
import { NextFunction } from 'express';
@Injectable()
export class ApiKeyMiddleware extends IntentMiddleware {
constructor(private service: UserService) {}
async use(req: Request, res: Response, next: NextFunction): Promise<void> {
next();
}
}
Let's say you want to throw some error from the middleware itself, you can throw an HttpException
error. This would automatically get captured by our error filter.
async use(req: Request, res: Response, next: NextFunction): Promise<void> {
const isApiKeyMatching = false; // add your logic here.
if (!isApiKeyMatching) {
throw new HttpException('API Keys mismatch. Please double check once!');
}
next();
}
Applying Middlewares
Now, after you are done with creating the middleware, you will now need to start using it. Intent supports following type of applications for the middlewares,
- Global Middleware - gets applied on all incoming routes
- Route Based Middleware - gets applied on specific routes, group of routes, or excluding some routes.
To apply the middleware globally, you can simply add the ApiKeyMiddleware
we built in the app/http/kernel.ts
.
import { Kernel, IntentMiddleware, Type, } from '@intentjs/core';
import { ApiKeyMiddleware } from './Middlewares/api-key';
export class HttpKernel extends Kernel {
/**
* Register all of your global middlewares here.
* Middlewares added in the return array will be
* applied to all routes by default.
*/
public middlewares(): Type<IntentMiddleware>[] {
return [
// existing middlewares here...
ApiKeyMiddleware
];
}
}
What if you don't want to apply a middleware globally, and instead just apply it on certain routes. For this, you can simply use the routeMiddlewares
available inside the Kernel
class.
import { Kernel, IntentMiddleware, Type, MiddlewareConfigurator } from '@intentjs/core';
import { ApiKeyMiddleware } from './middlewares/api-key';
export class HttpKernel extends Kernel {
/**
* Register all of your route specific middlewares here.
*/
public routeMiddlewares(configurator: MiddlewareConfigurator): Type<IntentMiddleware>[] {
configurator
.use(ApiKeyMiddleware)
.for(UserController);
}
}
This would apply the ApiKeyMiddleware
on all of the routes mentioned in the UserController
. If you don't want to pass the controller to the for
method, you can also pass a route. The route passed will be considered just a prefix.
configurator
.use(ApiKeyMiddleware)
.for('/users');
You can also exclude certain routes from this. This would then run the middleware on all of the routes except the ones mentioned explicitly.
configurator
.use(ApiKeyMiddleware)
.for('/users')
.exclude('/users/:id');
The above example applies the ApiKeyMiddleware
on all routes starting with /users
prefix, except the /users/:id
route.
You might have some routes with different HTTP Methods, and you wish to exclude a certain route with a certain method, you can pass { path: '/users/:id', method: RequestMethod.POST }
.
configurator
.use(ApiKeyMiddleware)
.for('/users')
.exclude({ path: '/users/:id', method: RequestMethod.POST });
The above configuration will run the ApiKeyMiddleware
on all routes starting with /users
, except the /users/:id
routes with POST method.