Skip to content

Why ergo?

ergo is a play on “error or go” — every middleware either rejects the request with a proper error or passes it forward. There is no ambiguity, no silent swallowing, no deferred validation. The name also carries its Latin meaning: therefore — as in, “the request is valid; therefore, proceed.”

Most Node.js frameworks treat middleware as a flat chain where anything can happen in any order. This leads to common failure modes:

  • Wasted work: body parsing and database queries execute before discovering the request is unauthorized.
  • Inconsistent errors: each handler invents its own error format, making client-side error handling fragile.
  • Silent failures: middleware swallows errors or returns ambiguous status codes, making debugging harder.
  • RFC drift: teams start with good intentions but gradually diverge from HTTP semantics because the framework doesn’t enforce them.

ergo organizes every request through four ordered stages:

Request → Negotiation → Authorization → Validation → Execution → Response
↓ ↓ ↓
406/415 401/403 400/422

Each stage either succeeds (passes the request forward) or fails (returns an RFC 9457 Problem Details error response). Failures are immediate — no downstream middleware executes.

Fail Fast is a well-established principle in systems design. The concept originates from Jim Shore’s influential essay “Fail Fast” (IEEE Software, 2004), which argues that bugs are easier to find when software fails immediately and visibly rather than producing incorrect results silently.

In the HTTP context, this principle maps directly to RFC 9110’s status code semantics: a 401 Unauthorized should be returned before attempting to parse a request body, and a 406 Not Acceptable should be returned before executing business logic. ergo makes this the only possible execution path.

ergo doesn’t just support RFCs — it enforces them structurally:

ConcernStandardergo Behavior
Error responsesRFC 9457All errors are Problem Details JSON
Content negotiationRFC 9110 §12.5Automatic 406 for unacceptable media types
AuthenticationRFC 6750, RFC 7617Bearer/Basic with proper WWW-Authenticate
CachingRFC 9111Cache-Control and conditional request support
CORSFetch StandardPreflight and simple request handling
CSRFOWASP GuidelinesDouble-submit cookie pattern
Rate limitingRFC 6585 §4429 Too Many Requests with Retry-After
Security headersRFC 6797HSTS, CSP, and security header defaults

ergo doesn’t treat security as an opt-in feature — it’s a consequence of the pipeline design and conservative defaults. You would have to deliberately override these protections to weaken them:

  • Security headers ship with restrictive defaults: Content-Security-Policy: default-src 'none', X-Frame-Options: DENY, X-Content-Type-Options: nosniff, X-XSS-Protection: 0 (disables flawed browser XSS filters).
  • Null-prototype objects for all user-input-derived data (query params, cookies, Prefer headers) prevent prototype pollution attacks.
  • Bounded input parsing limits query string length, key-value pair count, cookie count, request body size, and decompressed body size out of the box.
  • Decompression bomb protection enforces a separate limit on inflated body size after decompression, preventing small compressed payloads from expanding to arbitrary sizes in memory.
  • Header injection prevention via sanitizeQuotedString for all values interpolated into HTTP header quoted-strings (WWW-Authenticate, Link, Set-Cookie).
  • Timing-safe CSRF verification uses crypto.timingSafeEqual() to prevent timing attacks on token comparison.
  • Sensitive header redaction in the structured logger (authorization, cookie, proxy-authorization, set-cookie).
  • 5xx error detail redaction ensures internal error messages are never leaked to API consumers.

These protections satisfy the OWASP REST Security Cheat Sheet recommendations and address multiple risks in the OWASP API Security Top 10. See the Security concepts page for a detailed mapping.