Skip to main content

express-server

Express server patterns with TypeScript, InversifyJS, and Socket.IO. Use when creating or modifying HTTP endpoints, middleware, route handlers, CORS config, graceful shutdown, or writing supertest integration tests.

Informações da origem

Repositório
recca0120/code-quest
Última atividade na origem
19 de abril de 2026 às 22:05
Idioma detectado do SKILL.md
inglês
Estrelas
11
Forks
2

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
express-server
description
Express server patterns with TypeScript, InversifyJS, and Socket.IO. Use when creating or modifying HTTP endpoints, middleware, route handlers, CORS config, graceful shutdown, or writing supertest integration tests.
# Express Server Skill Stack: Express 4.x, TypeScript, ESM (`"type": "module"`), InversifyJS DI, Socket.IO, cors, helmet. The server is a **thin HTTP layer** — business logic lives in injected services, not in route files. --- ## Project Structure ``` src/ server/ app.ts # Express factory — creates and configures app, no listen() server.ts # Entry point — binds port, handles SIGTERM routes/ # One file per resource, returns express.Router middleware/ # Custom middleware (auth, logging, validation) errors/ # AppError class, error handler middleware ``` --- ## Middleware Ordering Register in this exact order — order is critical: ```ts app.use(helmet()); // 1. Security headers — first app.use(cors(corsOptions)); // 2. CORS — before body parsing app.use(express.json({ limit: '1mb' })); // 3. Body parsers app.use(rateLimiter); // 4. Rate limiting app.use('/static', express.static(staticDir, { maxAge: '1d' })); // 5. Static app.use('/health', healthRouter); // 6. Health — no auth needed app.use('/api', apiRouter); // 7. App routes app.use(errorHandler); // 8. Error handler — always last ``` --- ## Async Error Handling (Express 4) Express 4 does not catch async errors automatically. Wrap handlers or use `express-async-errors`. ```ts // Option A: wrapper (no extra dep) const asyncHandler = (fn: RequestHandler): RequestHandler => (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next); // Option B: import once in app.ts (patches express globally) import 'express-async-errors'; ``` Error middleware — must have exactly four parameters: ```ts app.use((err: unknown, req: Request, res: Response, _next: NextFunction) => { const status = err instanceof AppError ? err.status : 500; const message = err instanceof AppError ? err.message : 'Internal Server Error'; res.status(status).json({ error: message }); }); ``` --- ## Security ```ts import helmet from 'helmet'; import rateLimit from 'express-rate-limit'; app.use(helmet()); const corsOptions: CorsOptions = { origin: process.env.ALLOWED_ORIGINS?.split(',') ?? [], credentials: true, }; const limiter = rateLimit({ windowMs: 60_000, max: 100 }); app.use('/api', limiter); ``` Never use `origin: '*'` in production when `credentials: true`. --- ## Health Check ```ts healthRouter.get('/', (_req, res) => { res.json({ status: 'ok', uptime: process.uptime() }); }); ``` Kubernetes pattern: return `503` during shutdown to drain load balancer traffic before process exits. --- ## Graceful Shutdown ```ts const httpServer = app.listen(port); const shutdown = () => { httpServer.close(() => process.exit(0)); setTimeout(() => process.exit(1), 10_000).unref(); // force-kill after 10s }; process.on('SIGTERM', shutdown); process.on('SIGINT', shutdown); ``` For Socket.IO: call `io.close()` inside `shutdown` before `httpServer.close()`. --- ## InversifyJS Integration Resolve services from the container inside route factories — never `new`: ```ts export function createApiRouter(container: Container): Router { const router = Router(); const svc = container.get(MyService); router.get('/', asyncHandler(async (req, res) => { res.json(await svc.list()); })); return router; } ``` --- ## Testing with Supertest ```ts import request from 'supertest'; import { buildApp } from '../app.js'; const app = buildApp(testContainer); it('GET /health returns 200', async () => { await request(app).get('/health').expect(200); }); ``` Bind a real or stub container — avoid mocking the HTTP layer itself. --- ## Common Pitfalls - Forgetting `next(err)` in Express 4 async handlers causes silent hangs. - Registering error middleware with three params — it silently becomes a regular middleware. - Calling `app.listen()` inside the app factory breaks supertest (port conflicts). - Setting `origin: '*'` with `credentials: true` is rejected by browsers. - Static middleware before `helmet()` can serve files without security headers. - Not calling `io.close()` on shutdown leaves Socket.IO connections hanging. --- Sources: - [Express Error Handling](https://expressjs.com/en/guide/error-handling.html) - [Express Security Best Practices](https://expressjs.com/en/advanced/best-practice-security.html) - [Health Checks and Graceful Shutdown](https://expressjs.com/en/advanced/healthcheck-graceful-shutdown.html) - [Helmet.js](https://helmetjs.github.io/) - [Rate Limiting in Express.js — Better Stack](https://betterstack.com/community/guides/scaling-nodejs/rate-limiting-express/) - [Express Security Best Practices 2025 — Corgea](https://hub.corgea.com/articles/express-security-best-practices-2025)
Ver no GitHub