UNPKG

@elsikora/nestjs-crud-automator

Version:

A library for automating the creation of CRUD operations in NestJS.

101 lines (98 loc) 6.26 kB
import { __decorate } from '../external/tslib/tslib.es6.js'; import { randomUUID } from 'node:crypto'; import { Injectable, HttpStatus, HttpException, InternalServerErrorException } from '@nestjs/common'; import { ThrottlerException } from '@nestjs/throttler'; import { FormatUnknownForLog } from '../utility/format-unknown-for-log.utility.js'; import { LoggerUtility } from '../utility/logger.utility.js'; import { catchError } from 'rxjs/operators'; const interceptorLogger = LoggerUtility.getLogger("CorrelationIDResponseBodyInterceptor"); /** * Global interceptor that adds correlation IDs and timestamps to all error responses. * @see {@link https://elsikora.com/docs/nestjs-crud-automator/api-reference/interceptors | API Reference - Interceptors} * @see {@link https://elsikora.com/docs/nestjs-crud-automator/guides/error-handling | Guides - Error Handling} */ let CorrelationIDResponseBodyInterceptor = class CorrelationIDResponseBodyInterceptor { intercept(context, next) { const request = context.switchToHttp().getRequest(); const reply = context.switchToHttp().getResponse(); const rawCorrelationId = request.headers["x-correlation-id"]; const headerCorrelationId = Array.isArray(rawCorrelationId) ? rawCorrelationId.find((value) => value.trim().length > 0) : rawCorrelationId; const normalizedCorrelationId = typeof headerCorrelationId === "string" ? headerCorrelationId.trim() : undefined; const correlationId = normalizedCorrelationId && normalizedCorrelationId.length > 0 ? normalizedCorrelationId : randomUUID(); const requestMethod = request.method ?? "UNKNOWN_METHOD"; const requestUrl = request.url ?? "UNKNOWN_URL"; // Persist the resolved correlation ID for downstream loggers/middlewares request.headers["x-correlation-id"] = correlationId; request.correlationID = correlationId; reply.header("x-correlation-id", correlationId); return next.handle().pipe(catchError((error) => { if (error instanceof ThrottlerException) { const errorResponse = error.getResponse(); interceptorLogger.warn(`HTTP ${HttpStatus.TOO_MANY_REQUESTS} ${requestMethod} ${requestUrl} correlationID=${correlationId}`); let customErrorResponse = { statusCode: HttpStatus.TOO_MANY_REQUESTS }; if (typeof errorResponse === "object" && errorResponse != null) { customErrorResponse = { ...errorResponse }; } else { customErrorResponse.message = errorResponse; } customErrorResponse.error = "Too Many Requests"; customErrorResponse.timestamp = Date.now(); customErrorResponse.correlationID = correlationId; throw new HttpException(customErrorResponse, error.getStatus()); } else if (error instanceof HttpException) { const errorResponse = error.getResponse(); const status = error.getStatus(); if (status >= HttpStatus.INTERNAL_SERVER_ERROR) { const errorStack = error instanceof Error ? error.stack : undefined; interceptorLogger.error(`HTTP ${status} ${requestMethod} ${requestUrl} correlationID=${correlationId}`, errorStack); const cause = error.cause; if (cause instanceof Error) { interceptorLogger.error(`Cause: ${cause.name}: ${cause.message} correlationID=${correlationId}`, cause.stack); } else if (cause != null) { interceptorLogger.error(`Cause: ${FormatUnknownForLog(cause)} correlationID=${correlationId}`); } } let customErrorResponse = {}; if (typeof errorResponse === "object" && errorResponse != null) { customErrorResponse = { ...errorResponse }; } else { customErrorResponse.message = errorResponse; } customErrorResponse.correlationID = correlationId; customErrorResponse.timestamp = Date.now(); throw new HttpException(customErrorResponse, status); } else { if (error instanceof Error) { interceptorLogger.error(`HTTP ${HttpStatus.INTERNAL_SERVER_ERROR} ${requestMethod} ${requestUrl} correlationID=${correlationId} (non-HttpException)`, error.stack); if (error.cause instanceof Error) { interceptorLogger.error(`Cause: ${error.cause.name}: ${error.cause.message} correlationID=${correlationId}`, error.cause.stack); } else if (error.cause != null) { interceptorLogger.error(`Cause: ${FormatUnknownForLog(error.cause)} correlationID=${correlationId}`); } } else { interceptorLogger.error(`HTTP ${HttpStatus.INTERNAL_SERVER_ERROR} ${requestMethod} ${requestUrl} correlationID=${correlationId} (non-Error thrown): ${FormatUnknownForLog(error)}`); } if (!(error instanceof Error)) { error = new InternalServerErrorException("Unknown error"); } const internalError = error; const errorResponse = "Internal server error"; const customErrorResponse = { correlationID: correlationId, error: "Internal server error", message: errorResponse, statusCode: HttpStatus.INTERNAL_SERVER_ERROR, timestamp: Date.now() }; const status = "getStatus" in internalError && typeof internalError.getStatus === "function" ? internalError.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR; throw new HttpException(customErrorResponse, status); } })); } }; CorrelationIDResponseBodyInterceptor = __decorate([ Injectable() ], CorrelationIDResponseBodyInterceptor); export { CorrelationIDResponseBodyInterceptor }; //# sourceMappingURL=correlation-id-response-body.interceptor.js.map