Skip to main content

api-design

RESTful, GraphQL, gRPC, and API best practices

Quellinformationen

Repository
miles990/claude-software-skills
Letzte Quellaktivität
8. Januar 2026 um 05:30
Erkannte Sprache von SKILL.md
Chinesisch
Sterne
26
Forks
6

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

Datei-Explorer
4 Dateien

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
api-design
description
RESTful, GraphQL, gRPC, and API best practices
domain
software-design
version
1.0.0
tags
["rest","graphql","grpc","websocket","openapi","versioning"]
triggers
{"keywords":{"primary":["api","rest","restful","graphql","grpc","endpoint","openapi"],"secondary":["swagger","websocket","webhook","versioning","rate limit","pagination"]},"context_boost":["backend","microservice","integration","http"],"context_penalty":["frontend","ui","css"],"priority":"high"}
collaboration
{"prerequisites":[],"delegation_triggers":[{"trigger":"Implementation of API endpoints","delegate_to":"backend","context":"Framework-specific implementation patterns"},{"trigger":"Data model for API responses","delegate_to":"database","context":"Schema design, query requirements"},{"trigger":"API contract testing","delegate_to":"testing-strategies","context":"Contract tests, integration tests"}],"receives_context_from":[{"skill":"backend","receives":"[Truncated]"},{"skill":"database","receives":"[Truncated]"}],"provides_context_to":[{"skill":"backend","provides":"[Truncated]"},{"skill":"frontend","provides":"[Truncated]"},{"skill":"testing-strategies","provides":"[Truncated]"}]}
# API Design ## Overview Design principles for building APIs that are intuitive, consistent, and scalable. Covers REST, GraphQL, gRPC, and real-time protocols. --- ## RESTful API Design ### Resource Naming ``` ✅ Good (nouns, plural): GET /users # List users GET /users/123 # Get user POST /users # Create user PUT /users/123 # Update user DELETE /users/123 # Delete user ❌ Bad (verbs, actions): GET /getUsers POST /createUser POST /users/123/delete ``` ### Nested Resources ``` # Hierarchical relationship GET /users/123/orders # User's orders GET /users/123/orders/456 # Specific order # Alternative: Query parameter for filtering GET /orders?userId=123 # Filter orders by user # Rule: Nest max 2 levels deep ❌ /users/123/orders/456/items/789/reviews ✅ /order-items/789/reviews ``` ### HTTP Methods & Status Codes | Method | Purpose | Success | Error | |--------|---------|---------|-------| | GET | Read | 200 | 404 | | POST | Create | 201 | 400, 409 | | PUT | Replace | 200 | 400, 404 | | PATCH | Partial update | 200 | 400, 404 | | DELETE | Remove | 204 | 404 | ```typescript // Response structure interface ApiResponse<T> { data: T; meta?: { page: number; limit: number; total: number; }; } interface ApiError { error: { code: string; // Machine-readable message: string; // Human-readable details?: object; // Validation errors, etc. }; } ``` ### Pagination ```typescript // Offset-based (simple, has issues with large datasets) GET /users?page=2&limit=20 // Cursor-based (stable, performant) GET /users?cursor=eyJpZCI6MTIzfQ&limit=20 // Response { "data": [...], "meta": { "nextCursor": "eyJpZCI6MTQzfQ", "hasMore": true } } ``` ### Filtering & Sorting ```typescript // Query parameters GET /products?category=electronics&minPrice=100&maxPrice=500 GET /products?sort=-createdAt,name // - prefix for descending // Filter operators GET /users?age[gte]=18&age[lte]=65 GET /users?status[in]=active,pending GET /users?name[like]=john* ``` --- ## GraphQL Design ### Schema Design ```graphql type User { id: ID! email: String! name: String! posts(first: Int, after: String): PostConnection! createdAt: DateTime! } type Post { id: ID! title: String! content: String! author: User! comments: [Comment!]! } # Connections for pagination (Relay spec) type PostConnection { edges: [PostEdge!]! pageInfo: PageInfo! } type PostEdge { node: Post! cursor: String! } type Query { user(id: ID!): User users(first: Int, after: String, filter: UserFilter): UserConnection! } type Mutation { createUser(input: CreateUserInput!): CreateUserPayload! updateUser(id: ID!, input: UpdateUserInput!): UpdateUserPayload! } input CreateUserInput { email: String! name: String! password: String! } type CreateUserPayload { user: User errors: [Error!] } ``` ### Resolver Patterns ```typescript // N+1 prevention with DataLoader const userLoader = new DataLoader(async (ids: string[]) => { const users = await db.users.findMany({ where: { id: { in: ids } } }); return ids.map(id => users.find(u => u.id === id)); }); const resolvers = { Post: { author: (post, _, { loaders }) => loaders.user.load(post.authorId), }, }; // Field-level authorization const resolvers = { User: { email: (user, _, { currentUser }) => { if (currentUser.id !== user.id && !currentUser.isAdmin) { return null; // Hide from other users } return user.email; }, }, }; ``` ### Error Handling ```typescript // Union types for expected errors type CreatePostResult = Post | ValidationError | NotAuthorizedError // Or use errors field in payload type CreatePostPayload { post: Post errors: [CreatePostError!] } union CreatePostError = ValidationError | RateLimitError ``` --- ## gRPC Design ### Protocol Buffers ```protobuf syntax = "proto3"; package users.v1; service UserService { rpc GetUser(GetUserRequest) returns (GetUserResponse); rpc ListUsers(ListUsersRequest) returns (ListUsersResponse); rpc CreateUser(CreateUserRequest) returns (CreateUserResponse); // Streaming rpc WatchUsers(WatchUsersRequest) returns (stream UserEvent); rpc BatchCreateUsers(stream CreateUserRequest) returns (BatchCreateResponse); } message User { string id = 1; string email = 2; string name = 3; google.protobuf.Timestamp created_at = 4; } message GetUserRequest { string id = 1; } message GetUserResponse { User user = 1; } message ListUsersRequest { int32 page_size = 1; string page_token = 2; UserFilter filter = 3; } message ListUsersResponse { repeated User users = 1; string next_page_token = 2; } ``` ### When to Use gRPC | Use Case | REST | GraphQL | gRPC | |----------|------|---------|------| | Public API | ✅ | ✅ | ❌ | | Mobile apps | ✅ | ✅ | ⚠️ | | Microservices | ⚠️ | ❌ | ✅ | | Real-time | ❌ | ⚠️ | ✅ | | Browser clients | ✅ | ✅ | ⚠️ | --- ## API Versioning ### Strategies ``` # URL versioning (most common) GET /v1/users GET /v2/users # Header versioning GET /users Accept: application/vnd.api+json; version=2 # Query parameter GET /users?version=2 ``` ### Breaking vs Non-Breaking Changes ``` Non-Breaking (safe): ✅ Add new optional field ✅ Add new endpoint ✅ Add new optional query parameter ✅ Expand enum values (if client ignores unknown) Breaking (requires new version): ❌ Remove field ❌ Rename field ❌ Change field type ❌ Make optional field required ❌ Change URL structure ``` ### Deprecation Strategy ```typescript // OpenAPI deprecation /** * @deprecated Use /v2/users instead. Will be removed on 2025-06-01. */ app.get('/v1/users', ...); // Response header res.setHeader('Deprecation', 'true'); res.setHeader('Sunset', 'Sat, 01 Jun 2025 00:00:00 GMT'); res.setHeader('Link', '</v2/users>; rel="successor-version"'); ``` --- ## Real-time APIs ### WebSocket ```typescript // Server wss.on('connection', (ws) => { ws.on('message', (data) => { const message = JSON.parse(data); switch (message.type) { case 'subscribe': subscriptions.add(ws, message.channel); break; case 'unsubscribe': subscriptions.remove(ws, message.channel); break; } }); }); // Client const ws = new WebSocket('wss://api.example.com/ws'); ws.send(JSON.stringify({ type: 'subscribe', channel: 'orders:user:123' })); ws.onmessage = (event) => { const data = JSON.parse(event.data); handleUpdate(data); }; ``` ### Server-Sent Events (SSE) ```typescript // Server app.get('/events', (req, res) => { res.setHeader('Content-Type', 'text/event-stream'); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); const sendEvent = (data: object) => { res.write(`data: ${JSON.stringify(data)}\n\n`); }; // Subscribe to events eventEmitter.on('update', sendEvent); req.on('close', () => { eventEmitter.off('update', sendEvent); }); }); // Client const source = new EventSource('/events'); source.onmessage = (event) => { const data = JSON.parse(event.data); handleUpdate(data); }; ``` --- ## API Documentation ### OpenAPI (Swagger) ```yaml openapi: 3.0.3 info: title: User API version: 1.0.0 paths: /users: get: summary: List users parameters: - name: limit in: query schema: type: integer default: 20 responses: '200': description: Success content: application/json: schema: type: object properties: data: type: array items: $ref: '#/components/schemas/User' components: schemas: User: type: object required: [id, email, name] properties: id: type: string format: uuid email: type: string format: email name: type: string ``` --- ## Security Best Practices | Practice | Implementation | |----------|----------------| | Authentication | Bearer tokens, API keys | | Rate limiting | X-RateLimit-* headers | | Input validation | Schema validation (Zod, Joi) | | CORS | Whitelist allowed origins | | HTTPS | Always in production | | Request IDs | X-Request-ID for tracing | ```typescript // Rate limit headers res.setHeader('X-RateLimit-Limit', '100'); res.setHeader('X-RateLimit-Remaining', '95'); res.setHeader('X-RateLimit-Reset', '1640000000'); ``` --- ## Related Skills - [[architecture-patterns]] - API Gateway, microservices - [[security-practices]] - Authentication, authorization - [[documentation]] - API documentation tools --- ## Sharp Edges(常見陷阱) > 這些是 API 設計中最常見且代價最高的錯誤 ### SE-1: 破壞性變更 (Breaking Changes) - **嚴重度**: critical - **情境**: 修改現有 API 導致客戶端崩潰,沒有適當的版本控制 - **原因**: 刪除欄位、改變欄位類型、修改必填性、重新命名 - **症狀**: - 客戶端突然出現錯誤 - 舊版 App 無法使用 - 用戶投訴「昨天還能用,今天就壞了」 - **檢測**: `\-.*field|rename.*property|required.*true.*→.*false|type.*string.*→.*number` - **解法**: 使用 API 版本控制、只做 additive changes、設定 deprecation 期限 ### SE-2: 過度取得 (Over-fetching) - **嚴重度**: medium - **情境**: API 回傳太多客戶端不需要的資料 - **原因**: 「反正都有就回傳」的心態、沒有考慮不同使用場景 - **症狀**: - API 響應很大但客戶端只用其中一小部分 - 行動裝置載入緩慢 - 頻寬浪費 - **檢測**: `select\s*\*|findMany\(\)|findAll\(\)(?!.*select)` - **解法**: 使用 fields selection、GraphQL、按需求設計 endpoint ### SE-3: 取得不足 (Under-fetching) - **嚴重度**: medium - **情境**: 需要呼叫多個 API 才能取得完整資料 - **原因**: 過度細分 endpoint、沒有考慮常見使用場景
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen