Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | import { Injectable, NestInterceptor, ExecutionContext, CallHandler, Logger, } from '@nestjs/common'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; export interface ApiSuccessEnvelope<T> { success: true; data: T; meta: { requestId: string; correlationId: string; timestamp: string; page?: number; limit?: number; total?: number; totalPages?: number; }; } @Injectable() export class ApiResponseEnvelopeInterceptor implements NestInterceptor { private readonly logger = new Logger(ApiResponseEnvelopeInterceptor.name); intercept(context: ExecutionContext, next: CallHandler): Observable<any> { const request = context.switchToHttp().getRequest(); const requestId: string = request['requestId'] || 'unknown'; const correlationId: string = request['correlationId'] || 'unknown'; return next.handle().pipe( map((data) => { // If the response is already a standard envelope (i.e., from a legacy controller that wraps itself), pass through if (data && typeof data === 'object' && 'success' in data) { return data; } // PaginatedResult passthrough — merge meta if ( data && typeof data === 'object' && 'data' in data && 'meta' in data && Array.isArray(data.data) ) { return { success: true, data: data.data, meta: { ...data.meta, requestId, correlationId, timestamp: new Date().toISOString(), }, }; } return { success: true, data: data ?? null, meta: { requestId, correlationId, timestamp: new Date().toISOString(), }, }; }), ); } } |