@elsikora/nestjs-crud-automator
Version:
A library for automating the creation of CRUD operations in NestJS.
101 lines (98 loc) • 6.41 kB
JavaScript
;
var tslib_es6 = require('../external/tslib/tslib.es6.js');
var node_crypto = require('node:crypto');
var common = require('@nestjs/common');
var throttler = require('@nestjs/throttler');
var formatUnknownForLog_utility = require('../utility/format-unknown-for-log.utility.js');
var logger_utility = require('../utility/logger.utility.js');
var operators = require('rxjs/operators');
const interceptorLogger = logger_utility.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}
*/
exports.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 : node_crypto.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(operators.catchError((error) => {
if (error instanceof throttler.ThrottlerException) {
const errorResponse = error.getResponse();
interceptorLogger.warn(`HTTP ${common.HttpStatus.TOO_MANY_REQUESTS} ${requestMethod} ${requestUrl} correlationID=${correlationId}`);
let customErrorResponse = { statusCode: common.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 common.HttpException(customErrorResponse, error.getStatus());
}
else if (error instanceof common.HttpException) {
const errorResponse = error.getResponse();
const status = error.getStatus();
if (status >= common.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_utility.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 common.HttpException(customErrorResponse, status);
}
else {
if (error instanceof Error) {
interceptorLogger.error(`HTTP ${common.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_utility.FormatUnknownForLog(error.cause)} correlationID=${correlationId}`);
}
}
else {
interceptorLogger.error(`HTTP ${common.HttpStatus.INTERNAL_SERVER_ERROR} ${requestMethod} ${requestUrl} correlationID=${correlationId} (non-Error thrown): ${formatUnknownForLog_utility.FormatUnknownForLog(error)}`);
}
if (!(error instanceof Error)) {
error = new common.InternalServerErrorException("Unknown error");
}
const internalError = error;
const errorResponse = "Internal server error";
const customErrorResponse = { correlationID: correlationId, error: "Internal server error", message: errorResponse, statusCode: common.HttpStatus.INTERNAL_SERVER_ERROR, timestamp: Date.now() };
const status = "getStatus" in internalError && typeof internalError.getStatus === "function" ? internalError.getStatus() : common.HttpStatus.INTERNAL_SERVER_ERROR;
throw new common.HttpException(customErrorResponse, status);
}
}));
}
};
exports.CorrelationIDResponseBodyInterceptor = tslib_es6.__decorate([
common.Injectable()
], exports.CorrelationIDResponseBodyInterceptor);
//# sourceMappingURL=correlation-id-response-body.interceptor.js.map