@elsikora/nestjs-crud-automator
Version:
A library for automating the creation of CRUD operations in NestJS.
101 lines (98 loc) • 6.26 kB
JavaScript
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