feat(M01-A): 建立后端API基础骨架
This commit is contained in:
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user