63 lines
2.3 KiB
TypeScript

import 'dotenv/config';
import express from 'express';
import type { Response, NextFunction } from 'express';
import cors from 'cors';
import { z } from 'zod';
import swaggerUi from 'swagger-ui-express';
import { prisma } from './src/utils/prisma.js';
import { createOpenAPIDocument } from './src/openapi/registry.js';
import requestsRouter from './src/routes/requests.routes.js';
import itemsRouter from './src/routes/items.routes.js';
import catalogRouter from './src/routes/catalog.routes.js';
// ---------- App ----------
const app = express();
app.use(cors());
app.use(express.json());
// ---------- Health Check ----------
app.get('/health', (_req, res) => res.json({ ok: true, time: new Date().toISOString() }));
// ---------- Routes ----------
app.use('/api/consumable-temp-requests', requestsRouter);
app.use('/api/consumable-temp-items', itemsRouter);
app.use('/api/consumable-temp-catalog', catalogRouter);
// ---------- OpenAPI Documentation ----------
const openApiDocument = createOpenAPIDocument();
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(openApiDocument, {
customSiteTitle: '智能配送 API 文档',
customCss: '.swagger-ui .topbar { display: none }',
swaggerOptions: {
persistAuthorization: true,
displayRequestDuration: true
}
}));
app.get('/openapi.json', (_req, res) => {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(openApiDocument, null, 2));
});
// ---------- Error Handler ----------
// eslint-disable-next-line @typescript-eslint/no-unused-vars
app.use((err: any, _req: any, res: Response, _next: NextFunction) => {
if (err instanceof z.ZodError) {
return res.status(400).json({ error: 'VALIDATION_ERROR', details: err.flatten() });
}
if (err.message === 'NOT_FOUND') return res.status(404).json({ error: 'Not Found' });
console.error('Unhandled Error:', err);
res.status(500).json({ error: 'INTERNAL_ERROR' });
});
// ---------- Start Server ----------
const PORT = Number(process.env.PORT) || 3000;
app.listen(PORT, () => {
console.log(`Consumable Temp Request API listening on :${PORT}`);
});
// ---------- Graceful Shutdown ----------
process.on('SIGINT', async () => { await prisma.$disconnect(); process.exit(0); });
process.on('SIGTERM', async () => { await prisma.$disconnect(); process.exit(0); });