feat(M01-A): 建立后端API基础骨架

This commit is contained in:
Codex
2026-06-16 20:37:55 +08:00
parent eb259ce2a4
commit 98b66d22f2
22 changed files with 437 additions and 19 deletions
+54
View File
@@ -0,0 +1,54 @@
import { randomUUID } from 'node:crypto';
import cors from '@fastify/cors';
import rateLimit from '@fastify/rate-limit';
import Fastify, { type FastifyInstance } from 'fastify';
import { loadConfig, type AppConfig } from './config.js';
import { registerHealthRoutes } from './routes/health.js';
export interface BuildAppOptions {
config?: AppConfig;
}
declare module 'fastify' {
interface FastifyRequest {
traceId: string;
}
}
export async function buildApp(options: BuildAppOptions = {}): Promise<FastifyInstance> {
const config = options.config ?? loadConfig();
const app = Fastify({
logger: {
level: config.nodeEnv === 'test' ? 'silent' : 'info'
},
genReqId: () => randomUUID()
});
app.decorateRequest('traceId', '');
app.addHook('onRequest', async (request, reply) => {
const traceHeader = request.headers['x-trace-id'];
request.traceId = Array.isArray(traceHeader) ? traceHeader[0] : traceHeader || request.id;
reply.header('x-trace-id', request.traceId);
});
await app.register(cors, {
origin: config.corsOrigins
});
await app.register(rateLimit, {
max: 120,
timeWindow: '1 minute'
});
app.setErrorHandler((error, request, reply) => {
request.log.error({ err: error, traceId: request.traceId }, 'request failed');
reply.status(500).send({
code: 'INTERNAL_ERROR',
message: 'Internal server error',
traceId: request.traceId
});
});
await registerHealthRoutes(app, config);
return app;
}