
- Installs
- 65
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/miles990/claude-software-skills --skill api-design- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads api-design automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
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 |
// 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
// 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
// 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
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
// 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
// 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
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
// 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
// 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)
// 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)
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 |
// 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、沒有考慮常見使用場景
- 症狀:
- 前端需要 5+ 個 API 呼叫才能渲染一個頁面
- 複雜的前端資料整合邏輯
- N+1 API 請求問題
- 檢測:
Promise\.all\(.*fetch.*fetch.*fetch|\.then\(.*fetch - 解法: 設計聚合 endpoint、使用 include/expand 參數、考慮 BFF pattern
SE-4: 不一致的錯誤格式
- 嚴重度: high
- 情境: 不同 endpoint 回傳不同格式的錯誤,客戶端難以統一處理
- 原因: 沒有統一的錯誤處理規範、不同開發者各自實作
- 症狀:
- 有的錯誤用
error,有的用message,有的用errors - HTTP status code 使用不一致
- 客戶端需要寫很多 if-else 處理不同錯誤格式
- 有的錯誤用
- 檢測:
res\.json\(\{.*error|res\.json\(\{.*message|res\.status\(500\).*error - 解法: 定義統一的錯誤回應格式、使用 global error handler、建立錯誤碼系統
SE-5: 缺乏 Rate Limiting
- 嚴重度: critical
- 情境: API 沒有請求頻率限制,容易被濫用或攻擊
- 原因: 「先做出來再說」、不了解風險
- 症狀:
- DDoS 攻擊導致服務癱瘓
- 單一用戶耗盡所有資源
- 雲端帳單爆炸
- 檢測:
app\.use\((?!.*rateLimit)|router\.(?!.*limit)|express\(\)(?!.*rate) - 解法: 實作 rate limiting middleware、使用 Redis 追蹤請求、設定合理的限制
Validations
V-1: 禁止 HTTP status 200 回傳錯誤
- 類型: regex
- 嚴重度: high
- 模式:
res\.json\(\s*\{\s*error|res\.send\(\s*\{\s*error|\.json\(\{.*success:\s*false - 訊息: Error responses should use appropriate HTTP status codes (4xx/5xx)
- 修復建議: Use
res.status(400).json({ error: ... })for client errors - 適用:
*.ts,*.js
V-2: API 路徑使用動詞
- 類型: regex
- 嚴重度: medium
- 模式:
(get|create|update|delete|fetch|remove|add)\/|\/get|\/create|\/update|\/delete - 訊息: REST API paths should use nouns, not verbs (use HTTP methods instead)
- 修復建議: Change
/getUserstoGET /users,/createUsertoPOST /users - 適用:
*.ts,*.js
V-3: 缺少輸入驗證
- 類型: regex
- 嚴重度: critical
- 模式:
req\.body\.\w+(?!.*validate|.*schema|.*zod|.*joi|.*yup) - 訊息: Request body accessed without apparent validation
- 修復建議: Add validation with Zod/Joi before using request data
- 適用:
*.ts,*.js
V-4: 硬編碼 HTTP status code
- 類型: regex
- 嚴重度: low
- 模式:
res\.status\(\d{3}\) - 訊息: Consider using named status codes for readability
- 修復建議: Use
HttpStatus.OKor constants instead of magic numbers - 適用:
*.ts,*.js
V-5: 缺少 API 版本控制
- 類型: regex
- 嚴重度: medium
- 模式:
app\.(get|post|put|delete)\s*\(\s*['"]\/(?!v\d|api\/v\d) - 訊息: API route missing version prefix
- 修復建議: Add version prefix:
/api/v1/usersor use header-based versioning - 適用:
*.ts,*.js
FAQ
What does the api-design skill do?
RESTful, GraphQL, gRPC, and API best practices
How do I install api-design?
Run npx skills add https://github.com/miles990/claude-software-skills --skill api-design in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/api-design/ (personal) or .claude/skills/api-design/ (project).
Which AI agents can use api-design?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is api-design safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains api-design?
It is published by miles990 in miles990/claude-software-skills. It has 65 recorded installs.
More from miles990/claude-software-skills
code-quality
miles990/claude-software-skills
Clean code principles, SOLID, and code review practices
devops-cicd
miles990/claude-software-skills
CI/CD pipelines, infrastructure as code, and deployment strategies
game-development
miles990/claude-software-skills
Open the skill to read its SKILL.md instructions.
project-management
miles990/claude-software-skills
Open the skill to read its SKILL.md instructions.
e-commerce
miles990/claude-software-skills
Open the skill to read its SKILL.md instructions.
saas-platforms
miles990/claude-software-skills
Open the skill to read its SKILL.md instructions.
Popular backend & apis skills
find-skills
vercel-labs/skills
Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.
entra-app-registration
microsoft/azure-skills
Guides Microsoft Entra ID app registration, OAuth 2.0 authentication, and MSAL integration. USE FOR: create app registration, register Azure AD app, configure OAuth, set up authentication, add API permissions, generate service principal, MSAL example, console app auth, Entra ID setup, Azure AD authentication. DO NOT USE FOR: Key Vault secrets (use azure-keyvault-expiration-audit), general Azure resource security guidance.
google-agents-cli-adk-code
google/agents-cli
This skill should be used when the user wants to "write agent code", "build an agent with ADK", "add a tool", "create a callback", "define an agent", "use state management" — in a project that needs ADK (Agent Development Kit) API patterns and code examples. It provides a quick reference for agent types, tool definitions, orchestration patterns, callbacks, state management, the graph Workflow API, and reference recipes to study. Do NOT use for scaffolding (use google-agents-cli-scaffold) or deployment (use google-agents-cli-deploy).
embedded-captions
heygen-com/hyperframes
Add captions or subtitles to an existing single-subject talking-head video without editing the footage. Use for plain verbatim captions, cinematic captions embedded behind the subject, VFX captions, “炸/特效/酷炫字幕,” or a named identity from the 35-style catalog. Route by visual identity, not by backend engine. The quiet anchor rail is the default; embed every word only when the user explicitly wants a fully cinematic treatment. The workflow runs locally end to end, including transcription and subject matting; split multi-shot footage before applying it.
entra-agent-id
microsoft/azure-skills
Provision Microsoft Entra Agent Identity Blueprints, BlueprintPrincipals, and per-instance Agent Identities via Microsoft Graph, and configure OAuth 2.0 token exchange (fmipath, OBO, cross-tenant) including the Microsoft Entra SDK for AgentID sidecar. USE FOR: Agent Identity Blueprint, BlueprintPrincipal, agent OAuth, fmipath token exchange, agent OBO, Workload Identity Federation for agents, polyglot agent auth, Microsoft.Identity.Web.AgentIdentities. DO NOT USE FOR: standard Entra app registration (use entra-app-registration), Microsoft Foundry agent authoring (use microsoft-foundry).
neon
neondatabase/agent-skills
Overview of Neon, a complete set of cloud backend primitives around Lakebase Postgres: Auth, Object Storage, Functions, the AI Gateway, and Realtime. Start here to choose Neon for undecided login, files, APIs, and LLM calls, set up the CLI or MCP server, and follow the branch-first workflow. Use when building an app or backend on Neon, or when "Neon" or "Lakebase Postgres" is mentioned. Child skill neon-postgres wins for an existing DATABASEURL, SQL, schema, inspect, or search. Child skill neon-auth wins for login, users, sessions, identity routing, and Managed Better Auth setup. Child skill neon-realtime wins for live queries in reactive apps and agents. Also use for object storage, S3, buckets, serverless functions, function triggers, cron, AI gateway, LLM calls, realtime, logs, Loki, Grafana, observability, postgres, database, backend, Claimable Neon, neon.new, or a no-signup database.