64 lines
1.9 KiB
TypeScript
64 lines
1.9 KiB
TypeScript
|
|
import { randomUUID } from "node:crypto";
|
||
|
|
|
||
|
|
import type { HttpErrorResponseDTO } from "@metis/core/common";
|
||
|
|
import { registerCoreRoutes } from "@metis/core/module";
|
||
|
|
import type { Application, ErrorRequestHandler, RequestHandler } from "express";
|
||
|
|
import express from "express";
|
||
|
|
import helmet from "helmet";
|
||
|
|
|
||
|
|
import type { HttpLogger } from "./infrastructure/http/http-logger";
|
||
|
|
import { logHttpRequest } from "./infrastructure/http/http-logger";
|
||
|
|
|
||
|
|
export function createApp(
|
||
|
|
logger: HttpLogger = logHttpRequest,
|
||
|
|
identity?: { middleware: RequestHandler; register: (app: Application) => void }
|
||
|
|
) {
|
||
|
|
const app = express();
|
||
|
|
app.disable("x-powered-by");
|
||
|
|
app.use(helmet());
|
||
|
|
app.use((request, response, next) => {
|
||
|
|
const requestId = randomUUID();
|
||
|
|
const startedAt = performance.now();
|
||
|
|
response.setHeader("x-request-id", requestId);
|
||
|
|
response.setHeader("cache-control", "no-store");
|
||
|
|
response.once("finish", () => {
|
||
|
|
logger({
|
||
|
|
event: "http_request",
|
||
|
|
requestId,
|
||
|
|
method: request.method,
|
||
|
|
statusCode: response.statusCode,
|
||
|
|
durationMs: Math.round((performance.now() - startedAt) * 100) / 100,
|
||
|
|
});
|
||
|
|
});
|
||
|
|
next();
|
||
|
|
});
|
||
|
|
|
||
|
|
app.use(express.json({ limit: "64kb" }));
|
||
|
|
if (identity) {
|
||
|
|
app.use(identity.middleware);
|
||
|
|
identity.register(app);
|
||
|
|
}
|
||
|
|
registerCoreRoutes(app);
|
||
|
|
|
||
|
|
app.use((_request, response) => {
|
||
|
|
const error: HttpErrorResponseDTO = {
|
||
|
|
code: "NOT_FOUND",
|
||
|
|
requestId: response.getHeader("x-request-id")?.toString() ?? "",
|
||
|
|
};
|
||
|
|
response.status(404).json(error);
|
||
|
|
});
|
||
|
|
const errorHandler: ErrorRequestHandler = (_error: unknown, _request, response, next) => {
|
||
|
|
if (response.headersSent) {
|
||
|
|
next(_error);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const error: HttpErrorResponseDTO = {
|
||
|
|
code: "INTERNAL_ERROR",
|
||
|
|
requestId: response.getHeader("x-request-id")?.toString() ?? "",
|
||
|
|
};
|
||
|
|
response.status(500).json(error);
|
||
|
|
};
|
||
|
|
app.use(errorHandler);
|
||
|
|
return app;
|
||
|
|
}
|