typescript 42 lines · 8 steps

Request-scoped context service in NestJS

A request-scoped provider snapshots per-request metadata once at construction and exposes it safely to the rest of the app.

Explained by highlit
1import { Injectable, Scope, Inject } from '@nestjs/common';
2import { REQUEST } from '@nestjs/core';
3import { Request } from 'express';
4 
5export interface RequestContext {
6 requestId: string;
7 userId: string | null;
8 tenantId: string | null;
9 ip: string;
10}
11 
12@Injectable({ scope: Scope.REQUEST })
13export class RequestContextService {
14 private readonly context: RequestContext;
15 
16 constructor(@Inject(REQUEST) private readonly request: Request) {
17 const user = (request as Request & { user?: { id: string; tenantId?: string } }).user;
18 
19 this.context = {
20 requestId:
21 (request.headers['x-request-id'] as string) ?? crypto.randomUUID(),
22 userId: user?.id ?? null,
23 tenantId: user?.tenantId ?? (request.headers['x-tenant-id'] as string) ?? null,
24 ip: request.ip ?? request.socket.remoteAddress ?? 'unknown',
25 };
26 }
27 
28 get requestId(): string {
29 return this.context.requestId;
30 }
31 
32 requireTenantId(): string {
33 if (!this.context.tenantId) {
34 throw new Error('No tenant bound to the current request');
35 }
36 return this.context.tenantId;
37 }
38 
39 snapshot(): Readonly<RequestContext> {
40 return { ...this.context };
41 }
42}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Request-scoped providers give each HTTP request its own instance, so you can capture per-request state without threading it through every function.
  2. 2Computing derived context once in the constructor keeps reads cheap and guarantees a stable snapshot for the request's lifetime.
  3. 3Returning copies and requiring mandatory values guards callers from mutating shared state or silently proceeding with missing data.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Request-scoped context service in NestJS — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code