# API Designer

> Designs and reviews REST, GraphQL, and gRPC APIs following industry best practices. Use when creating new API endpoints, reviewing API contracts, generating OpenAPI/Swagger specifications, designing authentication flows, or optimizing API performance and developer experience.

- Skill: `mehdiozdemir/api-designer` (Agent Skill)
- Install (CLI): `npx skillmds@latest add mehdiozdemir/api-designer`
- Raw SKILL.md: https://api.skillmd.com/api/skills/mehdiozdemir/api-designer/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- Author: mehdiozdemir (https://skillmd.com/u/mehdiozdemir)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/mehdiozdemir/api-designer

---


# API Designer Skill

This skill helps design, review, and implement APIs following industry best practices. Use this whenever you need to create new APIs, review existing API designs, generate specifications, or improve API developer experience.

## API Design Principles

### 1. **REST API Fundamentals**

| Principle | Description |
|-----------|-------------|
| **Resource-Oriented** | URLs represent resources, not actions |
| **Stateless** | Each request contains all needed information |
| **Uniform Interface** | Consistent patterns across endpoints |
| **HATEOAS** | Responses include navigation links |
| **Cacheable** | Responses indicate cacheability |

### 2. **HTTP Methods**

| Method | Purpose | Idempotent | Safe | Request Body |
|--------|---------|------------|------|--------------|
| `GET` | Read resource | ✅ | ✅ | ❌ |
| `POST` | Create resource | ❌ | ❌ | ✅ |
| `PUT` | Replace resource | ✅ | ❌ | ✅ |
| `PATCH` | Partial update | ❌ | ❌ | ✅ |
| `DELETE` | Remove resource | ✅ | ❌ | ❌ |
| `HEAD` | Get headers only | ✅ | ✅ | ❌ |
| `OPTIONS` | Get allowed methods | ✅ | ✅ | ❌ |

### 3. **HTTP Status Codes**

**Success (2xx):**
| Code | Meaning | Use Case |
|------|---------|----------|
| `200` | OK | Successful GET, PUT, PATCH |
| `201` | Created | Successful POST |
| `202` | Accepted | Async operation started |
| `204` | No Content | Successful DELETE |

**Client Errors (4xx):**
| Code | Meaning | Use Case |
|------|---------|----------|
| `400` | Bad Request | Invalid input/validation error |
| `401` | Unauthorized | Missing/invalid authentication |
| `403` | Forbidden | Valid auth but insufficient permissions |
| `404` | Not Found | Resource doesn't exist |
| `405` | Method Not Allowed | Wrong HTTP method |
| `409` | Conflict | Duplicate/conflict with current state |
| `422` | Unprocessable Entity | Semantic validation error |
| `429` | Too Many Requests | Rate limit exceeded |

**Server Errors (5xx):**
| Code | Meaning | Use Case |
|------|---------|----------|
| `500` | Internal Server Error | Unexpected server error |
| `502` | Bad Gateway | Upstream service error |
| `503` | Service Unavailable | Maintenance/overload |
| `504` | Gateway Timeout | Upstream timeout |

## URL Design

### Resource Naming Conventions

```
# ✅ GOOD - Nouns, plural, lowercase, hyphens
GET /api/v1/users
GET /api/v1/users/123
GET /api/v1/users/123/orders
GET /api/v1/order-items

# ❌ BAD - Verbs, singular, camelCase
GET /api/v1/getUser
GET /api/v1/User/123
GET /api/v1/createOrder
GET /api/v1/orderItems
```

### Hierarchical Resources

```
# Parent-child relationships
GET /api/v1/users/123/orders              # User's orders
GET /api/v1/users/123/orders/456          # Specific order
GET /api/v1/users/123/orders/456/items    # Order items

# Limit nesting depth (max 2-3 levels)
# ❌ Too deep
GET /api/v1/users/123/orders/456/items/789/reviews

# ✅ Flatten with filters
GET /api/v1/reviews?order_item_id=789
```

### Query Parameters

```
# Filtering
GET /api/v1/products?category=electronics&status=active

# Sorting (use + for asc, - for desc)
GET /api/v1/products?sort=-created_at,+name

# Pagination
GET /api/v1/products?page=2&per_page=20
GET /api/v1/products?offset=20&limit=20
GET /api/v1/products?cursor=eyJpZCI6MTIzfQ

# Field selection (sparse fieldsets)
GET /api/v1/users/123?fields=id,name,email

# Including related resources
GET /api/v1/orders/123?include=customer,items
```

## Request/Response Design

### Request Structure

```json
// POST /api/v1/users
{
  "email": "user@example.com",
  "name": "John Doe",
  "password": "SecureP@ss123",
  "preferences": {
    "newsletter": true,
    "language": "en"
  }
}
```

### Response Structure

```json
// Standard response envelope
{
  "data": {
    "id": "usr_123abc",
    "type": "user",
    "attributes": {
      "email": "user@example.com",
      "name": "John Doe",
      "created_at": "2025-01-15T10:30:00Z"
    },
    "relationships": {
      "orders": {
        "links": {
          "related": "/api/v1/users/usr_123abc/orders"
        }
      }
    }
  },
  "meta": {
    "request_id": "req_xyz789"
  },
  "links": {
    "self": "/api/v1/users/usr_123abc"
  }
}
```

### Collection Response with Pagination

```json
{
  "data": [
    { "id": "usr_123", "name": "User 1" },
    { "id": "usr_456", "name": "User 2" }
  ],
  "meta": {
    "total_count": 150,
    "page": 2,
    "per_page": 20,
    "total_pages": 8
  },
  "links": {
    "self": "/api/v1/users?page=2&per_page=20",
    "first": "/api/v1/users?page=1&per_page=20",
    "prev": "/api/v1/users?page=1&per_page=20",
    "next": "/api/v1/users?page=3&per_page=20",
    "last": "/api/v1/users?page=8&per_page=20"
  }
}
```

### Error Response

```json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "The request could not be validated",
    "details": [
      {
        "field": "email",
        "code": "INVALID_FORMAT",
        "message": "Email must be a valid email address"
      },
      {
        "field": "password",
        "code": "TOO_SHORT",
        "message": "Password must be at least 8 characters"
      }
    ],
    "request_id": "req_xyz789",
    "documentation_url": "https://api.example.com/docs/errors#VALIDATION_ERROR"
  }
}
```

## Authentication & Authorization

### Authentication Methods

```yaml
# API Key (Header)
X-API-Key: sk_live_abc123xyz

# Bearer Token (JWT)
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

# Basic Auth (Not recommended for APIs)
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

# OAuth 2.0 Token
Authorization: Bearer ACCESS_TOKEN
```

### JWT Structure

```json
// Header
{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "key-id-123"
}

// Payload
{
  "sub": "usr_123abc",
  "iat": 1704963600,
  "exp": 1704967200,
  "iss": "https://api.example.com",
  "aud": "https://api.example.com",
  "scope": "read:users write:users",
  "roles": ["admin"],
  "email": "user@example.com"
}
```

### OAuth 2.0 Flows

```
# Authorization Code Flow (Web Apps)
1. Redirect to: /oauth/authorize?client_id=X&redirect_uri=Y&scope=Z&state=random
2. User authenticates and consents
3. Redirect back with: ?code=AUTH_CODE&state=random
4. Exchange code: POST /oauth/token (grant_type=authorization_code)
5. Receive: access_token + refresh_token

# Client Credentials Flow (Machine-to-Machine)
POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
&scope=read:data

# Token Refresh
POST /oauth/token
grant_type=refresh_token
&refresh_token=REFRESH_TOKEN
&client_id=YOUR_CLIENT_ID
```

## Versioning Strategies

### URL Path Versioning (Recommended)
```
GET /api/v1/users
GET /api/v2/users
```

### Header Versioning
```
GET /api/users
Accept: application/vnd.example.v1+json
X-API-Version: 1
```

### Query Parameter Versioning
```
GET /api/users?version=1
```

### Version Deprecation

```json
// Response headers for deprecated version
HTTP/1.1 200 OK
Deprecation: true
Sunset: Sat, 31 Dec 2025 23:59:59 GMT
Link: <https://api.example.com/v2/users>; rel="successor-version"

// Response body warning
{
  "data": { ... },
  "warnings": [
    {
      "code": "DEPRECATED_VERSION",
      "message": "API v1 is deprecated. Please migrate to v2 by Dec 31, 2025.",
      "documentation_url": "https://docs.example.com/migration/v1-to-v2"
    }
  ]
}
```

## OpenAPI Specification

### Basic Structure

```yaml
openapi: 3.1.0
info:
  title: User Management API
  description: API for managing users and their resources
  version: 1.0.0
  contact:
    name: API Support
    email: api-support@example.com
    url: https://example.com/support
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT

servers:
  - url: https://api.example.com/v1
    description: Production
  - url: https://staging-api.example.com/v1
    description: Staging
  - url: http://localhost:3000/v1
    description: Local development

tags:
  - name: Users
    description: User management operations
  - name: Orders
    description: Order processing

security:
  - BearerAuth: []
  - ApiKeyAuth: []
```

### Path Definition

```yaml
paths:
  /users:
    get:
      summary: List all users
      description: Returns a paginated list of users
      operationId: listUsers
      tags:
        - Users
      parameters:
        - name: page
          in: query
          description: Page number
          schema:
            type: integer
            default: 1
            minimum: 1
        - name: per_page
          in: query
          description: Items per page
          schema:
            type: integer
            default: 20
            maximum: 100
        - name: status
          in: query
          description: Filter by status
          schema:
            type: string
            enum: [active, inactive, pending]
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserList'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'

    post:
      summary: Create a user
      description: Creates a new user account
      operationId: createUser
      tags:
        - Users
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUserRequest'
            examples:
              basic:
                summary: Basic user
                value:
                  email: user@example.com
                  name: John Doe
                  password: SecureP@ss123
      responses:
        '201':
          description: User created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/ValidationError'
        '409':
          description: Email already exists
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /users/{userId}:
    parameters:
      - name: userId
        in: path
        required: true
        description: User ID
        schema:
          type: string
          pattern: '^usr_[a-zA-Z0-9]+$'

    get:
      summary: Get user by ID
      operationId: getUser
      tags:
        - Users
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '404':
          $ref: '#/components/responses/NotFound'

    patch:
      summary: Update user
      operationId: updateUser
      tags:
        - Users
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateUserRequest'
      responses:
        '200':
          description: User updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'

    delete:
      summary: Delete user
      operationId: deleteUser
      tags:
        - Users
      responses:
        '204':
          description: User deleted
        '404':
          $ref: '#/components/responses/NotFound'
```

### Schema Definitions

```yaml
components:
  schemas:
    User:
      type: object
      required:
        - id
        - email
        - name
        - created_at
      properties:
        id:
          type: string
          pattern: '^usr_[a-zA-Z0-9]+$'
          example: usr_123abc
          readOnly: true
        email:
          type: string
          format: email
          example: user@example.com
        name:
          type: string
          minLength: 1
          maxLength: 100
          example: John Doe
        status:
          type: string
          enum: [active, inactive, pending]
          default: pending
        created_at:
          type: string
          format: date-time
          readOnly: true
        updated_at:
          type: string
          format: date-time
          readOnly: true

    CreateUserRequest:
      type: object
      required:
        - email
        - name
        - password
      properties:
        email:
          type: string
          format: email
        name:
          type: string
          minLength: 1
          maxLength: 100
        password:
          type: string
          minLength: 8
          maxLength: 128
          format: password
          writeOnly: true

    UpdateUserRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
        status:
          type: string
          enum: [active, inactive]

    UserList:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/User'
        meta:
          $ref: '#/components/schemas/PaginationMeta'
        links:
          $ref: '#/components/schemas/PaginationLinks'

    PaginationMeta:
      type: object
      properties:
        total_count:
          type: integer
        page:
          type: integer
        per_page:
          type: integer
        total_pages:
          type: integer

    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
            message:
              type: string
            details:
              type: array
              items:
                type: object
                properties:
                  field:
                    type: string
                  code:
                    type: string
                  message:
                    type: string
            request_id:
              type: string

  responses:
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error:
              code: NOT_FOUND
              message: The requested resource was not found

    Unauthorized:
      description: Authentication required
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

    ValidationError:
      description: Validation failed
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

    RateLimited:
      description: Rate limit exceeded
      headers:
        X-RateLimit-Limit:
          schema:
            type: integer
        X-RateLimit-Remaining:
          schema:
            type: integer
        X-RateLimit-Reset:
          schema:
            type: integer
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'

  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
```

## GraphQL API Design

### Schema Definition

```graphql
type Query {
  # Get single user
  user(id: ID!): User
  
  # List users with filtering and pagination
  users(
    filter: UserFilter
    pagination: PaginationInput
    orderBy: UserOrderBy
  ): UserConnection!
  
  # Current authenticated user
  me: User
}

type Mutation {
  createUser(input: CreateUserInput!): CreateUserPayload!
  updateUser(id: ID!, input: UpdateUserInput!): UpdateUserPayload!
  deleteUser(id: ID!): DeleteUserPayload!
}

type User {
  id: ID!
  email: String!
  name: String!
  status: UserStatus!
  createdAt: DateTime!
  updatedAt: DateTime
  
  # Relationships
  orders(first: Int, after: String): OrderConnection!
  profile: UserProfile
}

enum UserStatus {
  ACTIVE
  INACTIVE
  PENDING
}

input UserFilter {
  status: UserStatus
  searchTerm: String
  createdAfter: DateTime
  createdBefore: DateTime
}

input PaginationInput {
  first: Int
  after: String
  last: Int
  before: String
}

input UserOrderBy {
  field: UserOrderField!
  direction: OrderDirection!
}

enum UserOrderField {
  CREATED_AT
  NAME
  EMAIL
}

enum OrderDirection {
  ASC
  DESC
}

# Relay-style connection
type UserConnection {
  edges: [UserEdge!]!
  pageInfo: PageInfo!
  totalCount: Int!
}

type UserEdge {
  node: User!
  cursor: String!
}

type PageInfo {
  hasNextPage: Boolean!
  hasPreviousPage: Boolean!
  startCursor: String
  endCursor: String
}

# Mutation payloads
input CreateUserInput {
  email: String!
  name: String!
  password: String!
}

type CreateUserPayload {
  user: User
  errors: [UserError!]
}

type UserError {
  field: String
  message: String!
  code: String!
}
```

## Rate Limiting

### Headers

```
X-RateLimit-Limit: 1000          # Max requests per window
X-RateLimit-Remaining: 999       # Remaining requests
X-RateLimit-Reset: 1704963600    # Unix timestamp when limit resets
Retry-After: 60                  # Seconds until retry (on 429)
```

### Rate Limit Tiers

```yaml
rate_limits:
  anonymous:
    requests_per_minute: 60
    requests_per_hour: 1000
  
  authenticated:
    requests_per_minute: 600
    requests_per_hour: 10000
  
  premium:
    requests_per_minute: 6000
    requests_per_hour: 100000

# Per-endpoint limits
endpoints:
  /auth/login:
    requests_per_minute: 5
    burst: 3
  
  /search:
    requests_per_minute: 30
  
  /export:
    requests_per_day: 10
```

## API Design Checklist

### Resource Design
- [ ] Resources named with nouns (plural)
- [ ] URL hierarchy reflects relationships
- [ ] Consistent naming conventions
- [ ] Max 2-3 nesting levels
- [ ] ID format documented

### Request/Response
- [ ] Consistent response envelope
- [ ] Proper status codes used
- [ ] Error responses include details
- [ ] Pagination implemented
- [ ] Sorting/filtering supported

### Security
- [ ] Authentication required
- [ ] Authorization enforced
- [ ] Input validation
- [ ] Rate limiting configured
- [ ] HTTPS enforced

### Documentation
- [ ] OpenAPI spec complete
- [ ] Examples provided
- [ ] Error codes documented
- [ ] Changelog maintained

### Developer Experience
- [ ] Consistent patterns
- [ ] Helpful error messages
- [ ] SDK/client examples
- [ ] Sandbox environment

## Output Format

When designing an API, provide:

```
## API Design Proposal

### Resource: [Resource Name]

#### Endpoints

| Method | Path | Description |
|--------|------|-------------|
| GET | /resource | List all |
| POST | /resource | Create |
| GET | /resource/{id} | Get one |
| PATCH | /resource/{id} | Update |
| DELETE | /resource/{id} | Delete |

#### Request/Response Examples

[Include examples for each endpoint]

#### OpenAPI Specification

```yaml
[OpenAPI spec for the resource]
```

#### Implementation Notes

- [Important consideration 1]
- [Important consideration 2]
```

## Notes

- Design APIs for consumers, not implementation
- Consistency is more important than perfection
- Version from the start
- Document as you design
- Consider backwards compatibility
- Plan for deprecation

