返回顶部
a

api-design-principles

# API Design Principles

作者: admin | 来源: ClawHub
源自
ClawHub
版本
V 1.0.0
安全检测
已通过
874
下载量
0
收藏
概述
安装方式
版本历史

api-design-principles

# 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 ```python 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) ```python GET /api/users?page=2&page_size=20 { "items": [...], "page": 2, "page_size": 20, "total": 150, "pages": 8 } ``` #### Cursor-Based (For Large Datasets) ```python 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: ```json { "error": { "code": "VALIDATION_ERROR", "message": "Request validation failed", "details": [ {"field": "email", "message": "Invalid email format"} ], "timestamp": "2025-10-16T12:00:00Z" } } ``` ### FastAPI Implementation ```python 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 ```graphql # 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) ```python 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 ```python # 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 ```python 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 <= 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

标签

skill ai

通过对话安装

该技能支持在以下平台通过对话安装:

OpenClaw WorkBuddy QClaw Kimi Claude

方式一:安装 SkillHub 和技能

帮我安装 SkillHub 和 api-design-principles-1776419943 技能

方式二:设置 SkillHub 为优先技能安装源

设置 SkillHub 为我的优先技能安装源,然后帮我安装 api-design-principles-1776419943 技能

通过命令行安装

skillhub install api-design-principles-1776419943

下载 Zip 包

⬇ 下载 api-design-principles v1.0.0

文件大小: 10 KB | 发布时间: 2026-4-17 18:23

v1.0.0 最新 2026-4-17 18:23
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.

Archiver·手机版·闲社网·闲社论坛·羊毛社区· 多链控股集团有限公司 · 苏ICP备2025199260号-1

Powered by Discuz! X5.0   © 2024-2025 闲社网·线报更新论坛·羊毛分享社区·http://xianshe.com

p2p_official_large
返回顶部