apitally
Version:
Simple API monitoring & analytics for REST APIs built with Express, Fastify, NestJS, AdonisJS, Hono, H3, Elysia, Hapi, and Koa.
113 lines • 5.3 kB
JavaScript
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import { performance } from "node:perf_hooks";
import { consumerFromStringOrObject } from "../common/consumerRegistry.js";
import { parseContentLength } from "../common/headers.js";
import { convertHeaders } from "../common/requestLogger.js";
const _ApitallyMiddleware = class _ApitallyMiddleware {
async handle(ctx, next) {
const client = await ctx.containerResolver.make("apitallyClient");
const logsContext = await ctx.containerResolver.make("apitallyLogsContext");
if (!client.isEnabled() || ctx.request.method().toUpperCase() === "OPTIONS") {
await next();
return;
}
return logsContext.run([], async () => {
var _a, _b;
const path = (_a = ctx.route) == null ? void 0 : _a.pattern;
const timestamp = Date.now() / 1e3;
const startTime = performance.now();
await next();
const responseTime = performance.now() - startTime;
const requestSize = parseContentLength(ctx.request.header("content-length"));
const requestContentType = (_b = ctx.request.header("content-type")) == null ? void 0 : _b.toString();
let responseStatus = ctx.response.getStatus();
let responseHeaders = ctx.response.getHeaders();
let responseSize;
let responseContentType;
const consumer = ctx.apitallyConsumer ? consumerFromStringOrObject(ctx.apitallyConsumer) : null;
client.consumerRegistry.addOrUpdateConsumer(consumer);
const onWriteHead = /* @__PURE__ */ __name((statusCode, headers) => {
var _a2;
responseStatus = statusCode;
responseHeaders = headers;
responseSize = parseContentLength(headers["content-length"]);
responseContentType = (_a2 = headers["content-type"]) == null ? void 0 : _a2.toString();
if (path) {
client.requestCounter.addRequest({
consumer: consumer == null ? void 0 : consumer.identifier,
method: ctx.request.method(),
path,
statusCode: responseStatus,
responseTime,
requestSize,
responseSize
});
if (responseStatus === 422 && ctx.apitallyError && "code" in ctx.apitallyError && "messages" in ctx.apitallyError && ctx.apitallyError.code === "E_VALIDATION_ERROR" && Array.isArray(ctx.apitallyError.messages)) {
ctx.apitallyError.messages.forEach((message) => {
client.validationErrorCounter.addValidationError({
consumer: consumer == null ? void 0 : consumer.identifier,
method: ctx.request.method(),
path,
loc: message.field,
msg: message.message,
type: message.rule
});
});
}
if (responseStatus === 500 && ctx.apitallyError) {
client.serverErrorCounter.addServerError({
consumer: consumer == null ? void 0 : consumer.identifier,
method: ctx.request.method(),
path,
type: ctx.apitallyError.name,
msg: ctx.apitallyError.message,
traceback: ctx.apitallyError.stack || ""
});
}
}
}, "onWriteHead");
const originalWriteHead = ctx.response.response.writeHead;
ctx.response.response.writeHead = (...args) => {
originalWriteHead.apply(ctx.response.response, args);
onWriteHead(args[0], typeof args[1] === "string" ? args[2] : args[1]);
return ctx.response.response;
};
if (client.requestLogger.enabled) {
const logs = logsContext.getStore();
const onEnd = /* @__PURE__ */ __name((chunk) => {
const requestBody = client.requestLogger.config.logRequestBody && client.requestLogger.isSupportedContentType(requestContentType) ? ctx.request.raw() : void 0;
const responseBody = client.requestLogger.config.logResponseBody && client.requestLogger.isSupportedContentType(responseContentType) ? chunk : void 0;
client.requestLogger.logRequest({
timestamp,
method: ctx.request.method(),
path,
url: ctx.request.completeUrl(true),
headers: convertHeaders(ctx.request.headers()),
size: requestSize,
consumer: consumer == null ? void 0 : consumer.identifier,
body: requestBody ? Buffer.from(requestBody) : void 0
}, {
statusCode: responseStatus,
responseTime: responseTime / 1e3,
headers: convertHeaders(responseHeaders),
size: responseSize,
body: responseBody ? Buffer.from(responseBody) : void 0
}, ctx.apitallyError, logs);
}, "onEnd");
const originalEnd = ctx.response.response.end;
ctx.response.response.end = (...args) => {
originalEnd.apply(ctx.response.response, args);
onEnd(typeof args[0] !== "function" ? args[0] : void 0);
return ctx.response.response;
};
}
});
}
};
__name(_ApitallyMiddleware, "ApitallyMiddleware");
let ApitallyMiddleware = _ApitallyMiddleware;
export {
ApitallyMiddleware as default
};
//# sourceMappingURL=middleware.js.map