# API Design — REST, GraphQL, and Contract-First Thinking

<!-- hint:slides topic="API design: REST principles, GraphQL tradeoffs, contract-first design, versioning, pagination, and error handling" slides="6" -->

## REST Principles

**REST** (Representational State Transfer) models the web as resources identified by URLs, manipulated via HTTP verbs.

| Principle | Meaning |
|-----------|---------|
| **Resources** | Nouns in URLs: `/users`, `/users/123`, `/users/123/orders` |
| **HTTP verbs** | GET (read), POST (create), PUT (replace), PATCH (partial update), DELETE (remove) |
| **Status codes** | 200 OK, 201 Created, 400 Bad Request, 404 Not Found, 429 Too Many Requests |
| **HATEOAS** | Responses include links to related resources (optional in practice) |

## REST Naming Conventions

- **Plural nouns:** `/users` not `/user`
- **Hierarchy:** `/users/123/orders`
- **No verbs in URL:** Use POST `/users` not `POST /createUser`
- **Snake_case or camelCase:** Be consistent (JSON often uses camelCase)

Example:

```http
GET /users/42/orders?status=active&limit=10
POST /users
{
  "email": "alice@example.com",
  "name": "Alice"
}
```

```mermaid
sequenceDiagram
    participant Client
    participant Gateway as API Gateway
    participant Server
    participant DB as Database
    Client->>Gateway: HTTP Request
    Gateway->>Server: Forward Request
    Server->>DB: Query
    DB-->>Server: Result
    Server-->>Gateway: Response
    Gateway-->>Client: HTTP Response
```

## GraphQL Basics

**GraphQL** lets clients request exactly the fields they need with a single endpoint.

```graphql
query {
  user(id: "42") {
    name
    email
    orders(limit: 5) {
      id
      total
    }
  }
}
```

- **Queries** — Read data
- **Mutations** — Create, update, delete
- **Schemas** — Strong typing; tools generate clients
- **Resolvers** — Server-side functions that fetch each field

## REST vs GraphQL

```mermaid
sequenceDiagram
    participant C as Client
    participant R as REST API
    participant G as GraphQL API
    C->>R: GET /users/1
    R-->>C: Full user object
    C->>R: GET /users/1/orders
    R-->>C: Orders
    Note over C,G: vs GraphQL
    C->>G: POST /graphql { user { name orders { total } } }
    G-->>C: Only requested fields, one round-trip
```

| Criterion | REST | GraphQL |
|-----------|------|--------|
| **Over-fetching** | Common (full objects) | Client specifies fields |
| **Under-fetching** | Multiple requests (N+1) | Single request, nested |
| **Caching** | HTTP cache, CDN | Custom (normalized cache) |
| **Discoverability** | URLs, OpenAPI | Schema, introspection |
| **Complexity** | Simpler | Schema, resolvers, tooling |

**Use REST** when: CRUD-heavy, HTTP caching matters, clients are simple. **Use GraphQL** when: flexible queries, mobile (bandwidth), many clients with different needs.

## Contract-First Design

Define the API before coding: **OpenAPI** (Swagger) for REST, **GraphQL schema** for GraphQL.

```yaml
# OpenAPI snippet
paths:
  /users/{id}:
    get:
      summary: Get user by ID
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: User object
        '404':
          description: Not found
```

Benefits: generate clients, mock servers, documentation, validation.

## API Versioning

| Strategy | Example | Pros / Cons |
|----------|---------|-------------|
| **URL** | `/v1/users`, `/v2/users` | Clear, cacheable; more URLs |
| **Header** | `Accept: application/vnd.api+json;version=2` | Clean URLs; less visible |
| **Query param** | `?version=2` | Simple; can be forgotten |
| **Media type** | `application/vnd.myapi.v2+json` | RESTful; verbose |

Common: **URL versioning** (`/v1/`, `/v2/`) — predictable, easy to route.

## Pagination

| Strategy | Use Case |
|----------|----------|
| **Offset** | `?offset=20&limit=10` — Simple, can skip; inconsistent if data changes |
| **Cursor** | `?cursor=abc123&limit=10` — Stable for feeds; no random access |
| **Page** | `?page=3&per_page=10` — Human-friendly; same issues as offset |

**Cursor-based** is preferred for feeds and infinite scroll.

## Error Handling

Return structured errors:

```json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid email format",
    "details": [
      { "field": "email", "reason": "Must be a valid email" }
    ]
  }
}
```

Use appropriate status codes: `400` (client error), `401` (unauthorized), `403` (forbidden), `404` (not found), `429` (rate limited), `500` (server error).

## Rate Limiting

Protect the API: return `429 Too Many Requests` and include headers:

```http
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 42
X-RateLimit-Reset: 1640995200
Retry-After: 60
```

## Authentication

| Method | Use Case |
|--------|----------|
| **API Key** | Simple, server-to-server |
| **OAuth 2.0** | Delegated access, user consent |
| **JWT** | Stateless, signed tokens; include in `Authorization: Bearer <token>` |

Always use HTTPS for credentials.

## Key Takeaways

- **REST:** Resources, verbs, status codes; good for CRUD
- **GraphQL:** Flexible queries, one endpoint; good for varied clients
- **Contract-first:** Define schema/OpenAPI before implementation
- **Version** explicitly (URL or header)
- **Pagination:** Prefer cursor for feeds
- **Errors:** Structured body, correct status codes
- **Rate limit** and **authenticate** securely
