-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.ts
More file actions
76 lines (68 loc) · 2.55 KB
/
app.ts
File metadata and controls
76 lines (68 loc) · 2.55 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/**
* Application factory — creates Express app with middleware only (no routes).
* No server.listen here: allows testing and microservice extraction.
* Env must be validated before calling (e.g. by importing config/env first).
* CORS is applied here so all routes benefit from origin validation and preflight.
*/
import express, { RequestHandler } from "express";
import type { ExpressApp, ExpressRequestLike, ExpressResponse } from "./types/express-app";
import cors from "cors";
import { env } from "./config/env/env-validation";
import { getCorsOptions } from "./config/cors/cors-options";
import { configureHelmet } from "./config/security/helmet-config";
import { requestIdMiddleware } from "./middlewares/request-id";
import { globalRateLimiter } from "./middlewares/global-rate-limit";
import { logger } from "./config/logger/logger-config";
export function createApp(): ExpressApp {
const app = express() as unknown as ExpressApp;
if (env.NODE_ENV === "production") {
app.set("trust proxy", 1);
}
app.use(requestIdMiddleware);
app.use(express.json({ limit: "100mb" }));
app.use(express.urlencoded({ extended: false, limit: "100mb" }));
app.use(globalRateLimiter);
app.use(cors(getCorsOptions()));
configureHelmet(app);
// Request logging (API routes only)
const requestLoggingMiddleware: RequestHandler = (
req: express.Request,
res: express.Response,
next: (err?: unknown) => void
) => {
const logReq = req as unknown as ExpressRequestLike;
const logRes = res as unknown as ExpressResponse;
const start = Date.now();
const path = logReq.path;
let capturedBody: Record<string, unknown> | undefined;
const originalJson = logRes.json.bind(res);
logRes.json = function (body: unknown) {
if (typeof body === "object" && body !== null) {
capturedBody = body as Record<string, unknown>;
}
return originalJson(body);
};
logRes.on("finish", () => {
if (path.startsWith("/api/")) {
const duration = Date.now() - start;
const meta = {
method: logReq.method,
path,
status: logRes.statusCode,
durationMs: duration,
requestId: logReq.requestId,
};
if (logRes.statusCode >= 500) {
logger.error("request", meta);
} else if (logRes.statusCode >= 400) {
logger.warn("request", meta);
} else {
logger.debug("request", capturedBody ? { ...meta, body: capturedBody } : meta);
}
}
});
next();
};
app.use(requestLoggingMiddleware);
return app;
}