API Error Contracts: The Missing Piece in Backend Reliability

Many APIs document success payloads but leave errors ad-hoc. Clients then implement fragile parsing logic and break on minor backend changes.

Step 1: Define typed error envelope

{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Too many requests",
    "retry_after_sec": 5
  }
}

Step 2: Return stable codes, variable messages

return res.status(429).json({
  error: { code: 'RATE_LIMITED', message: 'Request quota exceeded', retry_after_sec: 5 }
});

Step 3: Add contract tests for error shapes

expect(body.error.code).toBe('RATE_LIMITED');
expect(typeof body.error.retry_after_sec).toBe('number');

Pitfall

Using HTTP status code alone as client contract. You lose domain-specific handling paths.

Verification

  • Error codes remain backward-compatible across releases.
  • Clients can branch behavior using stable code fields.
  • Contract tests fail when envelope shape changes.

Get New Tutorials by Email

No spam. Just clear, practical breakdowns you can apply right away.

Enjoy this tutorial?

Get new practical tech tutorials in your inbox.