Claude Code Plugins

Community-maintained marketplace

Feedback

REST, GraphQL, and API design best practices. Use when designing APIs, defining contracts, or reviewing API architecture.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name api-design
description REST, GraphQL, and API design best practices. Use when designing APIs, defining contracts, or reviewing API architecture.

API Design Skill

Purpose

Design consistent, intuitive, and maintainable APIs following industry best practices.

REST API Design

URL Structure

https://api.example.com/v1/users/{userId}/orders/{orderId}
        └─────┬─────┘ └┬┘ └──────────────┬────────────────┘
           Base URL  Version          Resource Path

Conventions:

  • Use nouns, not verbs: /users not /getUsers
  • Use plural nouns: /users not /user
  • Use kebab-case: /user-profiles not /userProfiles
  • Nest resources logically: /users/{id}/orders
  • Limit nesting to 2 levels

HTTP Methods

Method Usage Idempotent Safe
GET Retrieve resource(s) Yes Yes
POST Create new resource No No
PUT Replace entire resource Yes No
PATCH Partial update No No
DELETE Remove resource Yes No

HTTP Status Codes

2xx Success
├── 200 OK              - Successful GET/PUT/PATCH
├── 201 Created         - Successful POST (with Location header)
├── 202 Accepted        - Async operation started
└── 204 No Content      - Successful DELETE

4xx Client Error
├── 400 Bad Request     - Invalid request body/params
├── 401 Unauthorized    - Missing/invalid authentication
├── 403 Forbidden       - Authenticated but not authorized
├── 404 Not Found       - Resource doesn't exist
├── 409 Conflict        - Resource conflict (duplicate)
├── 422 Unprocessable   - Validation failed
└── 429 Too Many Requests - Rate limited

5xx Server Error
├── 500 Internal Error  - Unexpected server error
├── 502 Bad Gateway     - Upstream service error
├── 503 Unavailable     - Service temporarily down
└── 504 Gateway Timeout - Upstream timeout

Request/Response Design

// POST /api/v1/users
// Request
{
  "email": "user@example.com",
  "name": "John Doe",
  "role": "user"
}

// Response (201 Created)
{
  "id": "usr_abc123",
  "email": "user@example.com",
  "name": "John Doe",
  "role": "user",
  "createdAt": "2024-01-15T10:30:00Z",
  "updatedAt": "2024-01-15T10:30:00Z"
}

Pagination

// GET /api/v1/users?page=2&limit=20

{
  "data": [...],
  "pagination": {
    "page": 2,
    "limit": 20,
    "total": 150,
    "totalPages": 8,
    "hasNext": true,
    "hasPrev": true
  },
  "links": {
    "self": "/api/v1/users?page=2&limit=20",
    "first": "/api/v1/users?page=1&limit=20",
    "prev": "/api/v1/users?page=1&limit=20",
    "next": "/api/v1/users?page=3&limit=20",
    "last": "/api/v1/users?page=8&limit=20"
  }
}

Filtering and Sorting

# Filtering
GET /api/v1/products?status=active&category=electronics
GET /api/v1/products?price[gte]=100&price[lte]=500
GET /api/v1/products?search=iphone

# Sorting
GET /api/v1/products?sort=price         # Ascending
GET /api/v1/products?sort=-price        # Descending
GET /api/v1/products?sort=-createdAt,name  # Multiple

# Field selection
GET /api/v1/users?fields=id,email,name

Error Response Format

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "The request data is invalid",
    "details": [
      {
        "field": "email",
        "message": "Must be a valid email address",
        "code": "INVALID_FORMAT"
      },
      {
        "field": "age",
        "message": "Must be at least 18",
        "code": "MIN_VALUE"
      }
    ],
    "requestId": "req_abc123",
    "timestamp": "2024-01-15T10:30:00Z"
  }
}

GraphQL Design

Schema Design

type User {
  id: ID!
  email: String!
  name: String!
  profile: Profile
  orders(first: Int, after: String): OrderConnection!
  createdAt: DateTime!
}

type Profile {
  bio: String
  avatar: URL
  location: String
}

type OrderConnection {
  edges: [OrderEdge!]!
  pageInfo: PageInfo!
  totalCount: Int!
}

type OrderEdge {
  node: Order!
  cursor: String!
}

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

Query Design

type Query {
  # Single resource
  user(id: ID!): User

  # List with filtering
  users(
    filter: UserFilter
    orderBy: UserOrderBy
    first: Int
    after: String
  ): UserConnection!

  # Search
  searchUsers(query: String!, limit: Int = 10): [User!]!
}

input UserFilter {
  status: UserStatus
  role: UserRole
  createdAfter: DateTime
}

enum UserOrderBy {
  CREATED_AT_ASC
  CREATED_AT_DESC
  NAME_ASC
  NAME_DESC
}

Mutation Design

type Mutation {
  # Create
  createUser(input: CreateUserInput!): CreateUserPayload!

  # Update
  updateUser(id: ID!, input: UpdateUserInput!): UpdateUserPayload!

  # Delete
  deleteUser(id: ID!): DeleteUserPayload!
}

input CreateUserInput {
  email: String!
  name: String!
  role: UserRole = USER
}

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

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

API Versioning

Strategies

Strategy Example Pros Cons
URL Path /v1/users Clear, cacheable Multiple codebases
Header Accept: application/vnd.api.v1+json Clean URLs Harder to test
Query Param /users?version=1 Easy to test Caching issues

Recommendation: URL path versioning for simplicity.

Deprecation Process

# Response headers for deprecated endpoints
Deprecation: true
Sunset: Sat, 1 Jan 2025 00:00:00 GMT
Link: </v2/users>; rel="successor-version"

Authentication & Authorization

Token-Based Auth

# Request
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

# Response for expired token (401)
WWW-Authenticate: Bearer realm="api",
                  error="invalid_token",
                  error_description="Token has expired"

API Key Auth

# Header approach (recommended)
X-API-Key: sk_live_abc123

# Query param (avoid - logs exposure)
GET /api/users?api_key=sk_live_abc123

OAuth 2.0 Scopes

Authorization: Bearer token

# Token includes scopes
{
  "scope": "read:users write:orders",
  "exp": 1705312200
}

Rate Limiting

Response Headers

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1705312200
Retry-After: 60

Rate Limit Response

// 429 Too Many Requests
{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Rate limit exceeded. Try again in 60 seconds.",
    "retryAfter": 60
  }
}

API Documentation (OpenAPI)

openapi: 3.0.3
info:
  title: User API
  version: 1.0.0
  description: API for managing users

paths:
  /users:
    get:
      summary: List users
      tags: [Users]
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserList'
        '401':
          $ref: '#/components/responses/Unauthorized'

components:
  schemas:
    User:
      type: object
      required: [id, email, name]
      properties:
        id:
          type: string
          example: usr_abc123
        email:
          type: string
          format: email
        name:
          type: string

API Design Checklist

Consistency

  • Consistent naming conventions
  • Consistent error format
  • Consistent pagination
  • Consistent date formats (ISO 8601)

Usability

  • Intuitive URL structure
  • Clear error messages
  • Comprehensive documentation
  • SDK/client libraries

Security

  • Authentication required
  • Rate limiting
  • Input validation
  • CORS configured
  • HTTPS only

Performance

  • Pagination for lists
  • Field selection
  • Caching headers
  • Compression

Maintainability

  • Versioning strategy
  • Deprecation policy
  • Changelog maintained
  • OpenAPI spec up-to-date