API Design
03 / 05

OpenAPI, Error Handling & Best Practices

API Design: OpenAPI, Errors & Best Practices

Error Response Format

Consistent error responses make APIs easier to consume. Use RFC 7807 (Problem Details) or a similar structure.

// RFC 7807 Problem Details (recommended)
{
  "type": "https://api.example.com/errors/validation",
  "title": "Validation Failed",
  "status": 422,
  "detail": "The request body contains invalid data",
  "instance": "/users/create",
  "errors": [
    { "field": "email", "message": "Must be a valid email address" },
    { "field": "password", "message": "Must be at least 8 characters" }
  ],
  "traceId": "abc123def456"
}

// Simpler format (also common)
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Validation failed",
    "details": [...],
    "requestId": "req_abc123"
  }
}

OpenAPI 3.1 Specification

openapi: 3.1.0
info:
  title: My API
  version: 1.0.0

paths:
  /users/{id}:
    get:
      summary: Get user by ID
      operationId: getUserById
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: User found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '404':
          description: User not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

components:
  schemas:
    User:
      type: object
      required: [id, email]
      properties:
        id:
          type: string
          format: uuid
        email:
          type: string
          format: email
        name:
          type: string
          nullable: true
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

Request & Response Design

  • Use camelCase for JSON fields (standard in JS ecosystem); snake_case is common in Python/Ruby APIs

  • Always return the created/updated resource in POST/PUT/PATCH responses — avoids extra GET request

  • Envelope vs. bare: return bare object for single resource, envelope { data, meta } for collections

  • Nullable vs. omitted: be explicit — undefined fields can cause confusion. Either always include or document which fields may be absent.

  • Dates: use ISO 8601 strings ("2026-05-07T14:30:00Z") — not Unix timestamps in JSON

  • IDs: use strings (UUIDs or opaque IDs) not integers — avoids enumeration attacks and handles large IDs

  • Partial responses: ?fields=id,name,email reduces payload for mobile clients

API Design Checklist

  • Resources are nouns, HTTP methods are verbs — no /getUser or /deletePost

  • Consistent naming: plural nouns (/users not /user), consistent casing

  • Proper status codes: 201 for create, 204 for delete, 422 for validation errors

  • Pagination on all list endpoints — never return unbounded lists

  • Rate limiting on all public endpoints — document limits in headers

  • Authentication documented: which endpoints require auth, what format

  • Error responses are consistent and include a requestId for debugging

  • Breaking changes get a new version — document deprecation timeline

  • OpenAPI spec is generated from code (not hand-written) — single source of truth

  • CORS configured for browser clients — explicit origins, not wildcard for authenticated APIs

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free