← 返回 Skills 市场
wpank

API Design Principles

作者 wpank · GitHub ↗ · v1.0.0
cross-platform ✓ 安全检测通过
942
总下载
0
收藏
12
当前安装
1
版本数
在 OpenClaw 中安装
/install api-design-principles
功能描述
Design clear, scalable REST and GraphQL APIs including resource modeling, HTTP methods, pagination, error handling, versioning, and schema best practices.
使用说明 (SKILL.md)

API Design Principles

WHAT

Design intuitive, scalable REST and GraphQL APIs that developers love. Covers resource modeling, HTTP semantics, pagination, error handling, versioning, and GraphQL schema patterns.

WHEN

  • Designing new REST or GraphQL APIs
  • Reviewing API specifications before implementation
  • Establishing API design standards for teams
  • Refactoring APIs for better usability
  • Migrating between API paradigms

KEYWORDS

REST, GraphQL, API design, HTTP methods, pagination, error handling, versioning, OpenAPI, HATEOAS, schema design


Decision Framework: REST vs GraphQL

Choose REST when... Choose GraphQL when...
Simple CRUD operations Complex nested data requirements
Public APIs with broad audience Mobile apps needing bandwidth optimization
Heavy caching requirements Clients need to specify exact data shape
Team is unfamiliar with GraphQL Aggregating multiple data sources
Simple response structures Rapidly evolving frontend requirements

REST API Design

Resource Naming Rules

✓ Plural nouns for collections
  GET /api/users
  GET /api/orders
  GET /api/products

✗ Avoid verbs (let HTTP methods be the verb)
  POST /api/createUser     ← Wrong
  POST /api/users          ← Correct

✓ Nested resources (max 2 levels)
  GET /api/users/{id}/orders
  
✗ Avoid deep nesting
  GET /api/users/{id}/orders/{orderId}/items/{itemId}/reviews  ← Too deep
  GET /api/order-items/{id}/reviews                            ← Better

HTTP Methods and Status Codes

Method Purpose Success Common Errors
GET Retrieve 200 OK 404 Not Found
POST Create 201 Created 400/422 Validation
PUT Replace 200 OK 404 Not Found
PATCH Partial update 200 OK 404 Not Found
DELETE Remove 204 No Content 404/409 Conflict

Complete Status Code Reference

SUCCESS = {
    200: "OK",           # GET, PUT, PATCH success
    201: "Created",      # POST success
    204: "No Content",   # DELETE success
}

CLIENT_ERROR = {
    400: "Bad Request",           # Malformed syntax
    401: "Unauthorized",          # Missing/invalid auth
    403: "Forbidden",             # Valid auth, no permission
    404: "Not Found",             # Resource doesn't exist
    409: "Conflict",              # State conflict (duplicate email)
    422: "Unprocessable Entity",  # Validation errors
    429: "Too Many Requests",     # Rate limited
}

SERVER_ERROR = {
    500: "Internal Server Error",
    503: "Service Unavailable",   # Temporary downtime
}

Pagination

Offset-Based (Simple)

GET /api/users?page=2&page_size=20

{
  "items": [...],
  "page": 2,
  "page_size": 20,
  "total": 150,
  "pages": 8
}

Cursor-Based (For Large Datasets)

GET /api/users?limit=20&cursor=eyJpZCI6MTIzfQ

{
  "items": [...],
  "next_cursor": "eyJpZCI6MTQzfQ",
  "has_more": true
}

Filtering and Sorting

# Filtering
GET /api/users?status=active&role=admin

# Sorting (- prefix for descending)
GET /api/users?sort=-created_at,name

# Search
GET /api/users?search=john

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

Error Response Format

Always use consistent structure:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      {"field": "email", "message": "Invalid email format"}
    ],
    "timestamp": "2025-10-16T12:00:00Z"
  }
}

FastAPI Implementation

from fastapi import FastAPI, Query, Path, HTTPException, status
from pydantic import BaseModel, Field, EmailStr
from typing import Optional, List
from datetime import datetime

app = FastAPI(title="API", version="1.0.0")

# Models
class UserCreate(BaseModel):
    email: EmailStr
    name: str = Field(..., min_length=1, max_length=100)

class User(BaseModel):
    id: str
    email: str
    name: str
    created_at: datetime

class PaginatedResponse(BaseModel):
    items: List[User]
    total: int
    page: int
    page_size: int
    pages: int

# Endpoints
@app.get("/api/users", response_model=PaginatedResponse)
async def list_users(
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
    status: Optional[str] = Query(None),
    search: Optional[str] = Query(None)
):
    """List users with pagination and filtering."""
    total = await count_users(status=status, search=search)
    offset = (page - 1) * page_size
    users = await fetch_users(limit=page_size, offset=offset, status=status, search=search)
    
    return PaginatedResponse(
        items=users,
        total=total,
        page=page,
        page_size=page_size,
        pages=(total + page_size - 1) // page_size
    )

@app.post("/api/users", response_model=User, status_code=status.HTTP_201_CREATED)
async def create_user(user: UserCreate):
    """Create new user."""
    if await user_exists(user.email):
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail={"code": "EMAIL_EXISTS", "message": "Email already registered"}
        )
    return await save_user(user)

@app.get("/api/users/{user_id}", response_model=User)
async def get_user(user_id: str = Path(...)):
    """Get user by ID."""
    user = await fetch_user(user_id)
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return user

@app.delete("/api/users/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_user(user_id: str):
    """Delete user."""
    if not await fetch_user(user_id):
        raise HTTPException(status_code=404, detail="User not found")
    await remove_user(user_id)

GraphQL API Design

Schema Structure

# Types
type User {
  id: ID!
  email: String!
  name: String!
  createdAt: DateTime!
  orders(first: Int = 20, after: String): OrderConnection!
}

# Pagination (Relay-style)
type OrderConnection {
  edges: [OrderEdge!]!
  pageInfo: PageInfo!
  totalCount: Int!
}

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

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

# Queries
type Query {
  user(id: ID!): User
  users(first: Int = 20, after: String, search: String): UserConnection!
}

# Mutations with Input/Payload pattern
input CreateUserInput {
  email: String!
  name: String!
  password: String!
}

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

type Error {
  field: String
  message: String!
  code: String!
}

type Mutation {
  createUser(input: CreateUserInput!): CreateUserPayload!
}

DataLoader (Prevent N+1)

from aiodataloader import DataLoader

class UserLoader(DataLoader):
    async def batch_load_fn(self, user_ids: List[str]) -> List[Optional[dict]]:
        """Load multiple users in single query."""
        users = await fetch_users_by_ids(user_ids)
        user_map = {user["id"]: user for user in users}
        return [user_map.get(uid) for uid in user_ids]

# In resolver
@user_type.field("orders")
async def resolve_orders(user: dict, info):
    loader = info.context["loaders"]["orders_by_user"]
    return await loader.load(user["id"])

Query Protection

# Depth limiting
MAX_QUERY_DEPTH = 5

# Complexity limiting
MAX_QUERY_COMPLEXITY = 100

# Timeout
QUERY_TIMEOUT_SECONDS = 10

Versioning Strategies

URL Versioning (Recommended)

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

Pros: Clear, easy to route, cacheable Cons: Multiple URLs for same resource

Header Versioning

GET /api/users
Accept: application/vnd.api+json; version=2

Pros: Clean URLs Cons: Less visible, harder to test

Deprecation Strategy

  1. Add deprecation headers: Deprecation: true
  2. Document migration path
  3. Give 6-12 months notice
  4. Monitor usage before removal

Rate Limiting

Headers

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 742
X-RateLimit-Reset: 1640000000

# When limited:
429 Too Many Requests
Retry-After: 3600

Implementation

from datetime import datetime, timedelta

class RateLimiter:
    def __init__(self, calls: int, period: int):
        self.calls = calls
        self.period = period
        self.cache = {}
    
    def check(self, key: str) -> tuple[bool, dict]:
        now = datetime.now()
        if key not in self.cache:
            self.cache[key] = []
        
        # Remove old requests
        cutoff = now - timedelta(seconds=self.period)
        self.cache[key] = [ts for ts in self.cache[key] if ts > cutoff]
        
        remaining = self.calls - len(self.cache[key])
        
        if remaining \x3C= 0:
            return False, {"limit": self.calls, "remaining": 0}
        
        self.cache[key].append(now)
        return True, {"limit": self.calls, "remaining": remaining - 1}

Pre-Implementation Checklist

Resources

  • Nouns, not verbs
  • Plural for collections
  • Max 2 levels nesting

HTTP

  • Correct method for each action
  • Correct status codes
  • Idempotent operations are idempotent

Data

  • All collections paginated
  • Filtering/sorting supported
  • Error format consistent

Security

  • Authentication defined
  • Rate limiting configured
  • Input validation on all fields
  • HTTPS enforced

Documentation

  • OpenAPI spec generated
  • All endpoints documented
  • Examples provided

NEVER

  • Verbs in URLs: /api/getUser → use /api/users/{id} with GET
  • POST for Retrieval: Use GET for safe, idempotent reads
  • Inconsistent Errors: Always same error format
  • Unbounded Lists: Always paginate collections
  • Secrets in URLs: Query params are logged
  • Breaking Changes Without Versioning: Plan for evolution from day 1
  • Database Schema as API: API should be stable even when schema changes
  • Ignoring HTTP Semantics: Status codes and methods have meaning
安全使用建议
This skill appears to be a documentation + example code package for API design and includes a runnable FastAPI template. It is coherent with its stated purpose. Before using the template in production: (1) replace placeholder implementations that return stub data with real database/auth logic, (2) remove or restrict CORS allow_origins=["*"] and avoid running the built-in uvicorn server bound to 0.0.0.0 on an exposed host without proper network controls, (3) add authentication, rate-limiting, and input validation as needed, and (4) confirm installation instructions (the README references a GitHub tree URL which may not install as-is). If you need the skill to run autonomously in an agent, note that it can be invoked by the agent but it does not request elevated privileges or credentials.
功能分析
Type: OpenClaw Skill Name: api-design-principles Version: 1.0.0 The skill bundle provides comprehensive documentation and a FastAPI code template for API design principles. All files, including SKILL.md and README.md, serve an educational or templating purpose without any evidence of malicious intent. The `templates/fastapi-template.py` includes a `CORSMiddleware` with `allow_origins=["*"]`, which is a common placeholder in development templates and explicitly advises configuration for production, not an indicator of malicious behavior. No data exfiltration, malicious execution, persistence, or harmful prompt injection attempts were found.
能力评估
Purpose & Capability
Name and intent (API design principles) match the included assets: a long SKILL.md with REST/GraphQL guidance, README, a FastAPI template, and a quick-reference. There are no unrelated binaries, env vars, or config paths requested.
Instruction Scope
SKILL.md contains guidance, examples, and code snippets only. It does not instruct the agent to read local secrets, call external endpoints beyond examples, or perform system-level operations. The examples are self-contained API design guidance and sample code (no data exfiltration steps).
Install Mechanism
No install spec is provided (instruction-only skill). Files are bundled with the skill (templates and docs) but no downloads, installers, or remote scripts are invoked by the skill itself.
Credentials
No environment variables, credentials, or config paths are required or declared. The content contains example code that expects typical production wiring (DB, auth) but does not request or embed credentials.
Persistence & Privilege
always is false and the skill does not request permanent system presence or modify other skills' configs. Autonomous invocation is allowed by default but that is platform-normal and not combined with other concerning privileges here.
如何使用
  1. 确保已安装 OpenClaw(本地或 Docker 部署)
  2. 在对话框中输入安装命令:/install api-design-principles
  3. 安装完成后,直接呼叫该 Skill 的名称或使用 /api-design-principles 触发
  4. 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
版本历史
v1.0.0
Initial release of API Design Principles skill. - Comprehensive guide for designing intuitive REST and GraphQL APIs, covering resource modeling, HTTP semantics, pagination, error handling, and versioning. - Includes decision framework for choosing between REST and GraphQL. - Provides clear examples and conventions for endpoint naming, filtering, sorting, status codes, and error response structures. - Offers ready-to-use FastAPI and GraphQL schema patterns, with practical implementation tips and code samples. - Covers API versioning and deprecation strategies, supporting both URL and header-based approaches.
元数据
Slug api-design-principles
版本 1.0.0
许可证
累计安装 15
当前安装数 12
历史版本数 1
常见问题

API Design Principles 是什么?

Design clear, scalable REST and GraphQL APIs including resource modeling, HTTP methods, pagination, error handling, versioning, and schema best practices. 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 942 次。

如何安装 API Design Principles?

在 OpenClaw 或 Claude Code 对话框中运行命令「/install api-design-principles」即可一键安装,无需额外配置。

API Design Principles 是免费的吗?

是的,API Design Principles 完全免费(开源免费),可自由下载、安装和使用。

API Design Principles 支持哪些平台?

API Design Principles 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。

谁开发了 API Design Principles?

由 wpank(@wpank)开发并维护,当前版本 v1.0.0。

💬 留言讨论