Anti-Patterns

7 API Design Anti-Patterns That Will Ruin Your Architecture

Real-world API anti-patterns that cause developer pain — inconsistent naming, swallowed errors, missing pagination, and no versioning. A guide to terrible API design.

A well-designed API is a joy to use. A poorly designed one? It’s a source of endless frustration, bugs, and wasted developer hours. Here are the most common API design mistakes I’ve encountered—and how to avoid them.

Mistake 1: Inconsistent Naming Conventions

Nothing frustrates developers more than an API that can’t decide on a naming convention.

# The nightmare API
GET /getUsers
GET /fetch-products
GET /Order_history
POST /createNewUser
POST /add_product

The fix: Pick a convention and stick to it religiously.

# Consistent REST API
GET /users
GET /products
GET /orders
POST /users
POST /products

Use:

  • Plural nouns for resources (/users, not /user)
  • Kebab-case for multi-word resources (/user-profiles)
  • HTTP verbs for actions, not URL verbs

Mistake 2: Ignoring HTTP Status Codes

Returning 200 OK for everything, including errors, is a cardinal sin.

// Bad - Returns 200 with error in body
{
  "success": false,
  "error": "User not found"
}

// Good - Returns 404 with helpful message
// HTTP 404 Not Found
{
  "error": {
    "code": "USER_NOT_FOUND",
    "message": "No user exists with ID 12345"
  }
}

Use status codes semantically:

  • 2xx - Success
  • 4xx - Client errors (bad request, unauthorized, not found)
  • 5xx - Server errors

Mistake 3: Poor Error Messages

Generic error messages waste everyone’s time.

// Bad
{ "error": "Invalid request" }

// Good
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      {
        "field": "email",
        "issue": "Must be a valid email address",
        "received": "not-an-email"
      }
    ]
  }
}

Good error messages include:

  • A machine-readable error code
  • A human-readable message
  • Details about what went wrong
  • Hints about how to fix it

Mistake 4: Not Versioning Your API

APIs evolve. Breaking changes without versioning break your consumers’ applications.

# Version in URL (most common)
GET /v1/users
GET /v2/users

# Version in header (cleaner URLs)
GET /users
Accept: application/vnd.myapi.v1+json

Start with v1 from day one. It costs nothing and saves future pain.

Mistake 5: Returning Too Much (or Too Little) Data

Over-fetching wastes bandwidth; under-fetching forces multiple requests.

// Over-fetching - returns everything
GET /users/123
{
  "id": 123,
  "name": "John",
  "email": "[email protected]",
  "password_hash": "...",  // Security issue!
  "internal_notes": "...",
  "created_at": "...",
  "updated_at": "...",
  // ... 50 more fields
}

// Better - return sensible defaults with field selection
GET /users/123?fields=id,name,email
{
  "id": 123,
  "name": "John",
  "email": "[email protected]"
}

Consider:

  • Field selection for customizing responses
  • Pagination for collections
  • Expansion for related resources (?expand=orders)

Mistake 6: Ignoring Pagination

Returning 10,000 records in one response is never okay.

// Good pagination response
{
  "data": [...],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total_pages": 50,
    "total_items": 1000
  },
  "links": {
    "self": "/users?page=1",
    "next": "/users?page=2",
    "last": "/users?page=50"
  }
}

Pagination strategies:

  • Offset-based - Simple but can skip items if data changes
  • Cursor-based - More reliable for real-time data
  • Keyset - Best for large datasets

Mistake 7: No Rate Limiting

Without rate limiting, one misbehaving client can bring down your entire API.

HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1640995200

HTTP/1.1 429 Too Many Requests
Retry-After: 60
{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Rate limit exceeded. Try again in 60 seconds."
  }
}

Rate limiting protects:

  • Your infrastructure from abuse
  • Fair usage across all clients
  • Your API from accidental infinite loops

Bonus: Document Everything

The best-designed API is useless if no one knows how to use it.

Use OpenAPI/Swagger to:

  • Generate interactive documentation
  • Enable client SDK generation
  • Validate requests and responses
  • Keep docs in sync with code

Conclusion

Great API design is about empathy for the developers who will use your API. Every decision should make their lives easier, not harder.

Remember:

  • Consistency is king
  • Errors are features, not afterthoughts
  • Plan for change from the start
  • When in doubt, follow REST conventions

Your API is a product. Treat it like one.


What API design patterns have you found most valuable? What mistakes would you add to this list?