AgentSkillsCN

api-rest-design

RESTful API 设计模式、版本控制与最佳实践

SKILL.md
--- frontmatter
name: api-rest-design
description: RESTful API design patterns, versioning, and best practices
license: MIT
compatibility: opencode

API REST Design Skill

Overview

This skill provides guidelines for designing RESTful APIs that are intuitive, maintainable, and scalable.

Core Principles

1. Resource-Based Design

code
✅ Good: /users, /orders, /products
❌ Bad: /getUsers, /createOrder, /deleteProduct

Resources should be nouns, not verbs.
HTTP methods define the action.

2. HTTP Methods

MethodActionIdempotentSafe
GETRead resourceYesYes
POSTCreate resourceNoNo
PUTFull update/replaceYesNo
PATCHPartial updateNoNo
DELETERemove resourceYesNo
http
GET    /users          # List all users
GET    /users/123      # Get specific user
POST   /users          # Create new user
PUT    /users/123      # Full update user 123
PATCH  /users/123      # Partial update user 123
DELETE /users/123      # Delete user 123

URL Design

1. Resource Hierarchy

http
✅ Good:
/users/123/orders           # Orders for user 123
/orders/456/items           # Items in order 456
/products/789/reviews       # Reviews for product 789

✅ Good (Alternative - flatter):
/orders?userId=123          # Filter orders by user
/order-items?orderId=456    # Filter items by order

2. Query Parameters

http
✅ Filtering:
/users?status=active&role=admin
/orders?status=pending&from=2024-01-01&to=2024-01-31

✅ Sorting:
/users?sort=-createdAt,name      # Sort by createdAt DESC, name ASC
/products?sort=price,-popularity  # Sort by price ASC, popularity DESC

✅ Pagination:
/users?page=2&limit=20           # Offset-based
/users?cursor=eyJpZCI6MTIzfQ==&limit=20  # Cursor-based (recommended)

✅ Field Selection:
/users?fields=id,email,name      # Sparse fieldsets

3. URL Naming

code
✅ Good:
- /users (plural)
- /user-profiles (kebab-case)
- /order-items (compound words)

❌ Bad:
- /user (singular - inconsistent)
- /userProfiles (camelCase)
- /user_profiles (snake_case)
- /UserProfiles (PascalCase)

Request/Response Design

1. Request Body (POST/PUT/PATCH)

json
{
  "email": "user@example.com",
  "username": "johndoe",
  "profile": {
    "firstName": "John",
    "lastName": "Doe"
  },
  "preferences": {
    "newsletter": true,
    "notifications": {
      "email": true,
      "sms": false
    }
  }
}

2. Response Structure

json
{
  "data": {
    "id": "usr_123",
    "email": "user@example.com",
    "username": "johndoe",
    "createdAt": "2024-01-15T10:30:00Z",
    "updatedAt": "2024-01-15T10:30:00Z"
  },
  "meta": {
    "requestId": "req_abc123",
    "timestamp": "2024-01-15T10:30:00Z"
  }
}

3. Collection Response

json
{
  "data": [
    { "id": "usr_1", "email": "user1@example.com" },
    { "id": "usr_2", "email": "user2@example.com" }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 100,
    "hasMore": true
  },
  "links": {
    "self": "/users?page=1&limit=20",
    "next": "/users?page=2&limit=20",
    "prev": null
  }
}

HTTP Status Codes

Success Codes

CodeMeaningUsage
200 OKSuccessGET, PUT, PATCH, DELETE
201 CreatedResource createdPOST
202 AcceptedAsync processing startedAsync operations
204 No ContentSuccess, no bodyDELETE, empty response
206 Partial ContentPartial successRange requests

Client Error Codes

CodeMeaningUsage
400 Bad RequestInvalid inputValidation errors
401 UnauthorizedAuthentication requiredMissing/invalid auth
403 ForbiddenInsufficient permissionsValid auth, no access
404 Not FoundResource doesn't existInvalid ID
409 ConflictResource conflictDuplicate entry
422 UnprocessableSemantic errorsBusiness logic errors
429 Too Many RequestsRate limit exceededThrottling

Server Error Codes

CodeMeaningUsage
500 Internal Server ErrorUnexpected errorUnhandled exceptions
502 Bad GatewayUpstream errorProxy/gateway issues
503 Service UnavailableTemporarily downMaintenance/overload

Error Response Format

json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      {
        "field": "email",
        "code": "INVALID_FORMAT",
        "message": "Must be a valid email address"
      },
      {
        "field": "age",
        "code": "OUT_OF_RANGE",
        "message": "Must be between 0 and 150"
      }
    ],
    "requestId": "req_abc123",
    "timestamp": "2024-01-15T10:30:00Z"
  }
}

Authentication & Security

1. Authentication Methods

http
✅ API Keys:
GET /api/users
Authorization: ApiKey abc123xyz

✅ Bearer Tokens (JWT):
GET /api/users
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

✅ OAuth 2.0:
POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&
client_id=CLIENT_ID&
client_secret=CLIENT_SECRET

2. Security Headers

http
Strict-Transport-Security: max-age=31536000; includeSubDomains
Content-Security-Policy: default-src 'self'
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block

3. Input Validation

go
// Request DTO with validation
type CreateUserRequest struct {
    Email    string `json:"email" validate:"required,email"`
    Username string `json:"username" validate:"required,min=3,max=50,alphanum"`
    Age      int    `json:"age" validate:"gte=0,lte=150"`
    Password string `json:"password" validate:"required,min=8"`
}

// Validation
if err := validate.Struct(req); err != nil {
    return c.Status(400).JSON(ErrorResponse{
        Code:    "VALIDATION_ERROR",
        Message: "Invalid request data",
        Details: formatValidationErrors(err),
    })
}

API Versioning

1. URL Path Versioning (Recommended)

http
/v1/users
/v2/users

✅ Pros:
- Clear and explicit
- Easy to route
- Cache-friendly

❌ Cons:
- URLs change

2. Header Versioning

http
Accept: application/vnd.api+json;version=2
Api-Version: 2

✅ Pros:
- Clean URLs
- Flexible

❌ Cons:
- Harder to discover
- Cache issues

3. Deprecation Strategy

http
HTTP/1.1 200 OK
Deprecation: true
Sunset: Sat, 01 Jun 2024 00:00:00 GMT
Link: </v2/users>; rel="successor-version"

{
  "warning": "This API version is deprecated and will be removed on 2024-06-01"
}

OpenAPI/Swagger Documentation

yaml
openapi: 3.0.0
info:
  title: Users API
  version: 1.0.0
  description: API for user management

paths:
  /users:
    get:
      summary: List users
      parameters:
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
      responses:
        '200':
          description: List of users
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/User'
                  pagination:
                    $ref: '#/components/schemas/Pagination'
    
    post:
      summary: Create user
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUserRequest'
      responses:
        '201':
          description: User created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          description: Validation error

components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: string
        email:
          type: string
          format: email
        username:
          type: string
        createdAt:
          type: string
          format: date-time

Rate Limiting

http
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640995200

429 Too Many Requests
Retry-After: 60

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded. Try again in 60 seconds.",
    "retryAfter": 60
  }
}

Best Practices

DO:

  • ✅ Use HTTPS in production
  • ✅ Validate all inputs
  • ✅ Use consistent naming conventions
  • ✅ Version your API from day one
  • ✅ Implement rate limiting
  • ✅ Return appropriate status codes
  • ✅ Support filtering, sorting, pagination
  • ✅ Document with OpenAPI/Swagger
  • ✅ Use caching headers
  • ✅ Implement idempotency keys for POST

DON'T:

  • ❌ Expose internal errors to clients
  • ❌ Use GET for operations with side effects
  • ❌ Store sensitive data in URLs
  • ❌ Ignore HTTP caching
  • ❌ Break backward compatibility without versioning
  • ❌ Return plain text instead of JSON
  • ❌ Use overly nested resources (>3 levels)

When to Use

Use this skill when:

  • Designing new APIs
  • Reviewing API designs
  • Implementing API endpoints
  • Writing API documentation
  • Planning API versioning strategy