Reliable apps treat errors as first-class outcomes. ApiNest returns standardized JSON error payloads and HTTP status codes; this guide shows patterns to recover gracefully, protect the user experience, and keep your systems healthy under stress.
Error model
{ "error": "RATE_LIMIT_MINUTE", "message": "Rate limit exceeded. Try again in a minute.", "retryAfter": 60 }
Idempotency
For write-like operations, ensure repeating a request has the same effect. Use a client-generated idempotency key where applicable.
Circuit breaker
class Circuit { constructor(limit = 5, cool = 30000){ this.fail = 0; this.openAt = 0; this.limit = limit; this.cool = cool } async run(fn){ if (Date.now() < this.openAt) throw new Error('CIRCUIT_OPEN') try { const v = await fn(); this.fail = 0; return v } catch (e){ this.fail++; if (this.fail >= this.limit){ this.openAt = Date.now() + this.cool } throw e } } }
UX guidance
- Show actionable copy for 401, 402, 429; hide stack traces for users.
- Provide a “Try again” with backoff on 429/503.
- Log correlation IDs to join user reports and server logs.
FAQ
How do I differentiate client vs server errors?
4xx are client issues (auth, limits, validation); 5xx are transient platform issues; retry accordingly.
Should I retry POSTs?
Only if the operation is idempotent; otherwise surface a safe “resume” step to the user.