Sun, 03/28/2021 - 13:36
Here is short example of how to create a shared request or HTTP context in a NestJS service.
In this example
- A middleware is used to set context data
- A Context provider is used to prodive context data
Let's start by defining a provider for http context
// request-context.ts
import { createParamDecorator, HttpException, HttpStatus, Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import httpContext from 'express-http-context';
@Injectable()
export class RequestContextProvider {
get(key) {
return httpContext.get(key)
}
set(key, value) {
return httpContext.set(key, value)
}
}
Next, Let's define a middleware
// request-context.ts
@Injectable()
export class RequestContextMiddleware implements NestMiddleware {
constructor(private requestContextProvider: RequestContextProvider) { }
use(req: Request, res: Response, next: NextFunction) {
// first run express-http-context middleware
httpContext.middleware(req, res, () => {
// set context data
// for example extract user data from JWT
const [, token] = req.headers.authorization.split(' ')
const decoded: Record<string, unknown> = jwt_decode(token)
this.requestContextProvider.set('userId', decoded.userId)
next();
})
}
}
In the application definition apply this middleware
//app.module.ts
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { RequestContextMiddleware, RequestContextProvider } from './common/request-context';
import { MyModule } from './my/my.module';
@Module({
imports: [MyModule],
providers: [RequestContextProvider]
})
export class AppModule implements NestModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(RequestContextMiddleware)
.forRoutes('*');
}
}
Now let's use this provider in our controllers
//my.controller.ts
import { Controller, Post } from '@nestjs/common';
@Controller('my')
export class MyController {
constructor(private requestContextProvider: RequestContextProvider) { }
@Post()
doSomething(): string {
const userId = this.requestContextProvider.get('userId')
// do something with user ID
//...
}
}
Another option is to provide decorators for wanted context data, for example a user ID from the context
// request-context.ts
import { createParamDecorator, HttpException, HttpStatus } from '@nestjs/common'
import httpContext from 'express-http-context'
export const UserId = createParamDecorator(() => {
const userId = httpContext.get('userId')
if (!userId) {
throw new HttpException(
'Missing authorization credentials',
HttpStatus.FORBIDDEN
)
}
return userId;
})
Authored by
Tags