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.
