API Design

← Back to System Design 101 | ← Previous: Message Queues

Introduction

Well-designed APIs are the contracts between services and clients. Poor API design leads to frustrated developers, brittle integrations, and maintenance nightmares. Good API design is invisibleβ€”it just works.

This article covers API design patterns I've used across REST, GraphQL, and gRPC implementations in production.

REST API Design

REST remains my default choice for most public-facing APIs.

Resource Naming

# Good API design - resource-oriented URLs
GET    /api/v1/users                 # List users
GET    /api/v1/users/{id}            # Get specific user
POST   /api/v1/users                 # Create user
PUT    /api/v1/users/{id}            # Update user (full)
PATCH  /api/v1/users/{id}            # Update user (partial)
DELETE /api/v1/users/{id}            # Delete user

# Nested resources
GET    /api/v1/users/{id}/orders     # List user's orders
GET    /api/v1/users/{id}/orders/{order_id}  # Get specific order

# Avoid verbs in URLs - use HTTP methods instead
❌ POST /api/v1/createUser
❌ GET  /api/v1/getUser?id=123
βœ… POST /api/v1/users
βœ… GET  /api/v1/users/123

FastAPI Implementation

API Versioning

Rate Limiting

Pagination

Idempotency

GraphQL API

GraphQL solves over-fetching and under-fetching problems in REST.

gRPC API

gRPC for high-performance internal service communication.

Error Handling

API Documentation

API Testing

Lessons Learned

What worked:

  1. REST for public APIs - widely understood

  2. GraphQL for complex data requirements

  3. gRPC for internal service communication

  4. Versioning from day one

  5. Comprehensive error responses

What didn't work:

  1. No API versioning strategy

  2. Inconsistent error responses

  3. Missing rate limiting

  4. Poor documentation

  5. Not implementing idempotency for critical operations

What's Next

Understanding API design, let's explore microservices patterns:


Navigation:

Last updated