返回 Skill 列表
extension
分类: 开发与工程无需 API Key

designing-apis

指导REST和GraphQL API设计、端点模式、请求/响应架构、版本控制以及API最佳实践。在构建API、设计端点或审查API合同时使用。

person作者: jakexiaohubgithub

Designing APIs

Principles and patterns for designing clean, consistent, and maintainable APIs.

When to Use This Skill

  • Designing new API endpoints
  • Reviewing API contracts
  • Planning API versioning strategies
  • Defining request/response schemas
  • Building GraphQL schemas
  • Documenting APIs

REST API Design Principles

Resource-Oriented Design

APIs should be organized around resources, not actions:

GOOD (Resource-oriented):
GET    /users           → List users
GET    /users/123       → Get user 123
POST   /users           → Create user
PUT    /users/123       → Update user 123
DELETE /users/123       → Delete user 123

BAD (Action-oriented):
POST   /getUsers
POST   /createUser
POST   /updateUser
POST   /deleteUser

HTTP Method Semantics

| Method | Purpose | Idempotent | Safe | Request Body | |--------|---------|------------|------|--------------| | GET | Retrieve resource(s) | Yes | Yes | No | | POST | Create resource | No | No | Yes | | PUT | Replace resource | Yes | No | Yes | | PATCH | Partial update | Yes | No | Yes | | DELETE | Remove resource | Yes | No | Optional |

URL Structure Patterns

Collection:     /users
Item:           /users/{id}
Nested:         /users/{id}/posts
Action:         /users/{id}/activate (POST only, for non-CRUD)
Filter:         /users?status=active&role=admin
Pagination:     /users?page=2&limit=20
Sort:           /users?sort=created_at&order=desc

Request Design

Path Parameters vs Query Parameters

| Use | Path Parameters | Query Parameters | |-----|-----------------|------------------| | Resource identification | /users/123 | - | | Required filters | /orgs/456/users | - | | Optional filters | - | ?status=active | | Pagination | - | ?page=2&limit=20 | | Sorting | - | ?sort=name&order=asc | | Search | - | ?q=searchterm |

Request Body Patterns

// POST /users - Create
{
  "email": "user@example.com",
  "name": "John Doe",
  "role": "admin"
}

// PATCH /users/123 - Partial update
{
  "name": "Jane Doe"
}

// Bulk operations - POST /users/bulk
{
  "operations": [
    { "action": "create", "data": { "email": "..." } },
    { "action": "update", "id": "123", "data": { "name": "..." } }
  ]
}

Response Design

Consistent Response Envelope

// Success response
{
  "data": { ... },
  "meta": {
    "timestamp": "2024-01-15T10:30:00Z",
    "requestId": "abc123"
  }
}

// Collection response with pagination
{
  "data": [ ... ],
  "meta": {
    "total": 100,
    "page": 2,
    "limit": 20,
    "hasMore": true
  }
}

// Error response
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid request data",
    "details": [
      { "field": "email", "message": "Invalid email format" }
    ]
  },
  "meta": {
    "timestamp": "2024-01-15T10:30:00Z",
    "requestId": "abc123"
  }
}

HTTP Status Code Guidelines

| Range | Category | Common Codes | |-------|----------|--------------| | 2xx | Success | 200 OK, 201 Created, 204 No Content | | 3xx | Redirect | 301 Moved, 304 Not Modified | | 4xx | Client Error | 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 422 Unprocessable | | 5xx | Server Error | 500 Internal, 502 Bad Gateway, 503 Unavailable |

Status Code Decision Tree

Success?
├─ Yes
│  ├─ Returning data? → 200 OK
│  ├─ Created resource? → 201 Created
│  └─ No content? → 204 No Content
└─ No
   ├─ Client's fault?
   │  ├─ Bad syntax? → 400 Bad Request
   │  ├─ Not authenticated? → 401 Unauthorized
   │  ├─ Not authorized? → 403 Forbidden
   │  ├─ Not found? → 404 Not Found
   │  └─ Validation failed? → 422 Unprocessable Entity
   └─ Server's fault? → 500 Internal Server Error

API Versioning Strategies

URL Path Versioning (Recommended)

/api/v1/users
/api/v2/users

Pros: Explicit, easy to understand, easy to route Cons: URL changes between versions

Header Versioning

GET /api/users
Accept: application/vnd.myapi.v2+json

Pros: Clean URLs Cons: Hidden version, harder to test

Query Parameter Versioning

/api/users?version=2

Pros: Flexible, easy to test Cons: Can be forgotten, pollutes query string


GraphQL Design Patterns

Schema-First Design

type User {
  id: ID!
  email: String!
  name: String!
  posts: [Post!]!
  createdAt: DateTime!
}

type Post {
  id: ID!
  title: String!
  content: String!
  author: User!
  createdAt: DateTime!
}

type Query {
  user(id: ID!): User
  users(filter: UserFilter, page: PageInput): UserConnection!
}

type Mutation {
  createUser(input: CreateUserInput!): User!
  updateUser(id: ID!, input: UpdateUserInput!): User!
  deleteUser(id: ID!): Boolean!
}

Input Types Pattern

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

input UpdateUserInput {
  email: String
  name: String
  role: Role
}

input UserFilter {
  status: UserStatus
  role: Role
  search: String
}

Pagination Patterns

# Cursor-based (recommended for large datasets)
type UserConnection {
  edges: [UserEdge!]!
  pageInfo: PageInfo!
}

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

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

# Offset-based (simpler, for smaller datasets)
type UserList {
  items: [User!]!
  total: Int!
  page: Int!
  limit: Int!
}

Authentication & Authorization

Authentication Patterns

| Pattern | Use Case | Header | |---------|----------|--------| | Bearer Token | Standard API auth | Authorization: Bearer <token> | | API Key | Server-to-server | X-API-Key: <key> | | Basic Auth | Simple/legacy systems | Authorization: Basic <base64> | | OAuth 2.0 | Third-party integration | OAuth flow |

Authorization Responses

Not authenticated → 401 Unauthorized
  (User identity unknown)

Not authorized → 403 Forbidden
  (User known, but lacks permission)

Error Handling Patterns

Standardized Error Format

{
  "error": {
    "code": "RESOURCE_NOT_FOUND",
    "message": "User with ID 123 not found",
    "target": "user",
    "details": [
      {
        "code": "INVALID_ID",
        "message": "The provided ID does not exist",
        "target": "id"
      }
    ],
    "innererror": {
      "trace": "abc123",
      "timestamp": "2024-01-15T10:30:00Z"
    }
  }
}

Common Error Codes

| Code | HTTP Status | When | |------|-------------|------| | VALIDATION_ERROR | 400/422 | Request data invalid | | UNAUTHORIZED | 401 | Auth required | | FORBIDDEN | 403 | Insufficient permissions | | NOT_FOUND | 404 | Resource doesn't exist | | CONFLICT | 409 | State conflict (duplicate) | | RATE_LIMITED | 429 | Too many requests | | INTERNAL_ERROR | 500 | Server failure |


API Documentation

OpenAPI/Swagger Structure

openapi: 3.0.3
info:
  title: My API
  version: 1.0.0

paths:
  /users:
    get:
      summary: List users
      parameters:
        - name: status
          in: query
          schema:
            type: string
            enum: [active, inactive]
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserList'

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

Anti-Patterns to Avoid

  1. Verbs in URLs - Use /users not /getUsers
  2. Ignoring HTTP Methods - Use proper methods, not POST for everything
  3. Inconsistent Naming - Pick snake_case or camelCase, stick with it
  4. Leaking Implementation - Don't expose internal IDs or DB structure
  5. Missing Pagination - Always paginate collections
  6. Ignoring Idempotency - PUT/DELETE must be idempotent
  7. No Versioning - Plan for API evolution from day one

Quick Reference

RESOURCE DESIGN:
  /resources           → Collection
  /resources/{id}      → Item
  /resources/{id}/sub  → Nested

HTTP METHODS:
  GET     → Read (safe, idempotent)
  POST    → Create (not idempotent)
  PUT     → Replace (idempotent)
  PATCH   → Update (idempotent)
  DELETE  → Remove (idempotent)

STATUS CODES:
  200 OK, 201 Created, 204 No Content
  400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found
  500 Internal Server Error

VERSIONING:
  /api/v1/resources (recommended)

PAGINATION:
  ?page=2&limit=20 (offset)
  ?cursor=abc123&limit=20 (cursor)