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.

インストールへ移動

ソース情報

リポジトリ
recca0120/code-quest
ソースの最終更新活動
2026年4月19日 22:05
検出された SKILL.md の言語
英語
スター
11
フォーク
2

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
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)
GitHubで見る