← 返回
未分类 中文

ia-nodejs-backend

Node.js backend patterns: layered architecture, TypeScript, validation, error handling, security, deployment. Use when building REST APIs, REST endpoints, mi...
Node.js 后端模式:分层架构、TypeScript、验证、错误处理、安全、部署。适用于构建 REST API、REST 端点、微服务。
iliaal iliaal 来源
未分类 clawhub v4.1.4 3 版本 100000 Key: 无需
★ 0
Stars
📥 755
下载
💾 0
安装
3
版本
#latest

概述

Node.js Backend

Verify before implementing: For framework-specific APIs (Express 5, Fastify 5, Node.js 22+ built-ins), look up current docs via Context7 (query-docs) before writing code. Training data may lag current releases.

Framework Selection

ContextChooseWhy
----------------------
Edge/ServerlessHonoZero-dep, fastest cold starts
Performance APIFastifyHigher throughput than Express, built-in schema validation
Enterprise/teamNestJSDI, decorators, structured conventions
Legacy/ecosystemExpressMost middleware, widest adoption

Ask user: deployment target, cold start needs, team experience, existing codebase.

Architecture

src/
├── routes/          # HTTP: parse request, call service, format response
├── middleware/       # Auth, validation, rate limiting, logging
├── services/        # Business logic (no HTTP types)
├── repositories/    # Data access only (queries, ORM)
├── config/          # Env, DB pool, constants
└── types/           # Shared TypeScript interfaces
  • Routes never contain business logic
  • Services never import Request/Response
  • Repositories never throw HTTP errors
  • Dependencies point inward only (Clean Architecture rule): routes -> services -> repositories. Never the reverse.
  • For scripts/prototypes: single file is fine -- ask "will this grow?"

TypeScript Rules

  • Use import type { } for type-only imports -- eliminates runtime overhead
  • Prefer interface for object shapes (2-5x faster type resolution than intersections)
  • Prefer unknown over any -- forces explicit narrowing
  • Use z.infer as single source of truth -- never duplicate types and schemas
  • Minimize as assertions -- use type guards instead
  • Add explicit return types to exported functions (faster declaration emit)
  • Untyped package? declare module 'pkg' { const v: unknown; export default v; } in types/ambient.d.ts

Validation

Zod (TypeScript inference) or TypeBox (Fastify native). Validate at boundaries only: request entry, before DB ops, env vars at startup. Use .extend(), .pick(), .omit(), .partial(), .merge() for DRY schemas.

Error Handling

Custom error hierarchy: AppError(message, statusCode, isOperational)ValidationError(400), NotFoundError(404), UnauthorizedError(401), ForbiddenError(403), ConflictError(409)

Centralized handler middleware:

  • AppError → return { error: message } with statusCode
  • Unknown → log full stack, return 500 + generic message in production
  • Async wrapper: const asyncHandler = (fn) => (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next);

Codes: 400 bad input | 401 no auth | 403 no permission | 404 missing | 409 conflict | 422 business rule | 429 rate limited | 500 server fault

API Design

Contract-first: define route schemas (Zod schemas, Fastify JSON Schema, or OpenAPI spec) before writing handler logic. The schema is the contract -- implementation follows. Generate OpenAPI/Swagger docs from these schemas for interactive API documentation.

  • Hyrum's Law awareness: every observable response field, ordering, or timing becomes a dependency for callers. Use Zod schemas or Fastify response schemas to control exactly what's serialized -- never return raw ORM objects or untyped objects from handlers.
  • Addition over modification: add new optional fields rather than changing or removing existing ones. Removing a field from a response schema breaks callers silently. Deprecate first (mark in OpenAPI spec), remove in a later version.
  • Consistent error envelope: all errors -- validation, auth, not-found, application -- must produce the same { error: { code, message, details? } } structure. Centralize in the error handler middleware. Callers build error handling once; inconsistent errors force per-endpoint special cases.
  • Boundary validation: validate at the middleware/route handler level (Zod .parse() on request body/params, Fastify schema validation). Services and repositories trust that input was validated at entry -- no redundant checks scattered through business logic.
  • Third-party responses are untrusted data: validate shape and content of external API responses before using them in logic, rendering, or decision-making. A compromised or misbehaving service can return unexpected types, malicious content, or missing fields. Parse through a Zod schema before use.
  • Resources: plural nouns (/users), max 2 nesting levels (/users/:id/orders)
  • Methods: GET read | POST create | PUT replace | PATCH partial | DELETE remove
  • Versioning: URL path /api/v1/
  • Response: { data, pagination?: { page, limit, total, totalPages } }
  • Queries: ?page=1&limit=20&status=active&sort=createdAt,desc
  • Return Location header on 201. Use 204 for successful DELETE with no body.

Async Patterns

PatternUse When
-------------------
async/awaitSequential operations
Promise.allParallel independent ops
Promise.allSettledParallel, some may fail
Promise.raceTimeout or first-wins

Never use readFileSync or other sync methods in production -- use fs.promises or stream equivalents. Offload CPU work to worker threads (Piscina). Stream large payloads.

Production Resilience

  • Fail-fast env validation: parse and validate all environment variables at startup with a Zod schema (const env = envSchema.parse(process.env)). If invalid, crash before serving traffic. Never discover a missing env var on the first request that needs it.
  • Health endpoints: expose both /health (shallow, always 200 if process is alive) and /ready (deep, verifies database, cache, and critical dependencies are reachable). Load balancers probe /ready for traffic routing; monitoring probes /health for process liveness. Don't conflate them.
  • Caching: Redis cache-aside for DB/API responses; in-memory LRU with TTL for hot paths. Always invalidate on writes.
  • Load shedding: @fastify/under-pressure (or equivalent) -- monitor event loop delay, heap, RSS; return 503 when thresholds exceeded.
  • Response schemas: In Fastify, always define response schemas -- enables fast-json-stringify for 2-3x faster serialization.
  • Circuit breaker: use opossum for outbound service calls. States: CLOSED (normal) -> OPEN (failing, return fallback) -> HALF_OPEN (probe). Prevents cascade failures when downstream services are down.

Observability

  • Define "working" before instrumenting: write the questions an on-call engineer will ask when this is broken at 3am ("which dependency is timing out?", "is it all users or one tenant?"), then add only the telemetry that answers them. Instrumentation with no question behind it is cost and noise.
  • Pick the signal by the question it answers: logs = "what happened in this one case?" (high-detail, structured, sampled under load); metrics = "how often / how fast / how saturated?" (cheap aggregates — keep label cardinality bounded, never user IDs or request IDs as labels); traces = "where did the time or the error go across services?".
  • Structured logging: pino with a stable set of event names and a correlation/request ID propagated through async context (AsyncLocalStorage). Never console.log in production paths.
  • Metrics: prom-client for RED per route — Rate (request count), Errors (error count), Duration (latency histogram). OpenTelemetry Node SDK for distributed traces across services.
  • Initialize tracing before app imports, then verify it fires: the OTel SDK must start before the modules it instruments are required, or auto-instrumentation silently no-ops. Before relying on any signal, force an error and send test traffic in staging and confirm the log/metric/trace actually lands — untested instrumentation fails silent.
  • Alert on symptoms, not causes: page on user-visible symptoms (error-rate spike, latency SLO burn, /ready flapping), not on causes (CPU high, heap growing). A cause with no symptom is a dashboard, not a page.

Discipline

  • Simplicity first -- every change as simple as possible, impact minimal code
  • Only touch what's necessary -- avoid introducing unrelated changes
  • No hacky workarounds -- if a fix feels wrong, step back and implement the clean solution
  • Before adding a new abstraction, verify it appears in 3+ places. If not, inline it.
  • If a fix requires bypassing TypeScript (as any, non-null assertions on untrusted data, // @ts-ignore), treat it as a design smell and find the typed solution
  • Verify: tsc --noEmit && npm test pass with zero warnings before declaring done

Verify

  • tsc --noEmit passes with zero errors
  • npm test passes with zero failures
  • No TypeScript bypasses (as any, @ts-ignore) in new code

References

版本历史

共 3 个版本

  • v4.1.4 当前
    2026-06-22 12:07
  • v4.1.0
    2026-06-03 12:53
  • v3.0.5
    2026-05-01 09:33 安全 安全

安全检测

腾讯云安全 (Keen)

队列中

腾讯云安全 (Sanbu)

队列中

🔗 相关推荐

ai-agent

ia-brainstorming

iliaal
前期探索:深度访谈、方案对比、设计文档。用于对模糊需求或创意进行细化、澄清等场景。
★ 0 📥 889
dev-programming

Github

steipete
使用 `gh` CLI 与 GitHub 交互,通过 `gh issue`、`gh pr`、`gh run` 和 `gh api` 管理议题、PR、CI 运行及高级查询。
★ 681 📥 329,365
dev-programming

CodeConductor.ai

larsonreever
AI驱动平台,提供快速全栈开发、智能体、工作流自动化及低代码AI集成的可扩展产品创建。
★ 76 📥 182,428