api-design-patterns
35
总安装量
35
周安装量
#5909
全站排名
安装命令
npx skills add https://github.com/asyrafhussin/agent-skills --skill api-design-patterns
Agent 安装分布
claude-code
25
gemini-cli
24
opencode
24
antigravity
22
github-copilot
18
Skill 文档
API Design Patterns
RESTful API design principles, error handling, pagination, versioning, and security best practices. Guidelines for building consistent, developer-friendly APIs.
When to Apply
Reference these guidelines when:
- Designing new API endpoints
- Reviewing existing API structure
- Implementing error handling
- Setting up pagination/filtering
- Planning API versioning
Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Resource Design | CRITICAL | rest- |
| 2 | Error Handling | CRITICAL | error- |
| 3 | Security | CRITICAL | sec- |
| 4 | Pagination & Filtering | HIGH | page- |
| 5 | Versioning | HIGH | ver- |
| 6 | Response Format | MEDIUM | resp- |
| 7 | Documentation | MEDIUM | doc- |
Quick Reference
1. Resource Design (CRITICAL)
rest-nouns-not-verbs– Use nouns for endpointsrest-plural-resources– Use plural resource namesrest-http-methods– Correct HTTP method usagerest-nested-resources– Proper resource nestingrest-status-codes– Appropriate status codesrest-idempotency– Idempotent operationsrest-hateoas– Hypermedia links
2. Error Handling (CRITICAL)
error-consistent-format– Consistent error structureerror-meaningful-messages– Helpful error messageserror-validation-details– Field-level validation errorserror-codes– Machine-readable error codeserror-stack-traces– Never expose in production
3. Security (CRITICAL)
sec-authentication– Proper auth implementationsec-authorization– Resource-level permissionssec-rate-limiting– Prevent abusesec-input-validation– Validate all inputsec-cors– CORS configurationsec-sensitive-data– Protect sensitive data
4. Pagination & Filtering (HIGH)
page-cursor-based– Cursor pagination for large datasetspage-offset-based– Offset pagination for simple casespage-consistent-params– Consistent parameter namespage-metadata– Include pagination metadatafilter-query-params– Filter via query parameterssort-flexible– Flexible sorting options
5. Versioning (HIGH)
ver-url-path– Version in URL pathver-header-based– Version in headersver-backward-compatible– Maintain compatibilityver-deprecation– Deprecation strategy
6. Response Format (MEDIUM)
resp-consistent-structure– Consistent response enveloperesp-json-conventions– JSON naming conventionsresp-partial-responses– Field selectionresp-compression– Response compression
7. Documentation (MEDIUM)
doc-openapi– OpenAPI/Swagger specdoc-examples– Request/response examplesdoc-changelog– API changelog
Essential Guidelines
Resource Naming
# â Verbs in URLs - RPC style
GET /getUsers
POST /createUser
PUT /updateUser/123
DELETE /deleteUser/123
# â
Nouns with HTTP methods - REST style
GET /users # List users
POST /users # Create user
GET /users/123 # Get user
PUT /users/123 # Update user (full)
PATCH /users/123 # Update user (partial)
DELETE /users/123 # Delete user
Nested Resources
# â
Logical nesting (max 2 levels)
GET /users/123/orders # User's orders
GET /users/123/orders/456 # Specific order
POST /users/123/orders # Create order for user
# â Too deeply nested
GET /users/123/orders/456/items/789/reviews
# â
Flatten when appropriate
GET /order-items/789/reviews # Direct access
HTTP Methods & Status Codes
# GET - Retrieve resource(s)
GET /users â 200 OK + array
GET /users/123 â 200 OK + object
GET /users/999 â 404 Not Found
# POST - Create resource
POST /users â 201 Created + object + Location header
POST /users (invalid) â 400 Bad Request + errors
# PUT - Full update (replace)
PUT /users/123 â 200 OK + updated object
PUT /users/999 â 404 Not Found
# PATCH - Partial update
PATCH /users/123 â 200 OK + updated object
# DELETE - Remove resource
DELETE /users/123 â 204 No Content
DELETE /users/999 â 404 Not Found
# Other common status codes
401 Unauthorized # Not authenticated
403 Forbidden # Authenticated but not authorized
409 Conflict # Resource state conflict
422 Unprocessable # Validation failed
429 Too Many Requests # Rate limited
500 Internal Error # Server error
503 Service Unavailable # Maintenance/overload
Error Response Format
// â Inconsistent error formats
{ "error": "Not found" }
{ "message": "Invalid email" }
{ "errors": ["Error 1", "Error 2"] }
// â
Consistent error envelope
{
"error": {
"code": "VALIDATION_ERROR",
"message": "The request contains invalid data",
"details": [
{
"field": "email",
"code": "INVALID_FORMAT",
"message": "Please provide a valid email address"
},
{
"field": "password",
"code": "TOO_SHORT",
"message": "Password must be at least 8 characters"
}
],
"request_id": "req_abc123"
}
}
// â
Not found error
{
"error": {
"code": "NOT_FOUND",
"message": "User with ID 123 not found",
"request_id": "req_def456"
}
}
// â
Server error (no sensitive details)
{
"error": {
"code": "INTERNAL_ERROR",
"message": "An unexpected error occurred. Please try again.",
"request_id": "req_ghi789"
}
}
Pagination
// â
Offset-based pagination
GET /users?page=2&per_page=20
{
"data": [...],
"meta": {
"current_page": 2,
"per_page": 20,
"total_pages": 10,
"total_count": 195
},
"links": {
"first": "/users?page=1&per_page=20",
"prev": "/users?page=1&per_page=20",
"next": "/users?page=3&per_page=20",
"last": "/users?page=10&per_page=20"
}
}
// â
Cursor-based pagination (for large datasets)
GET /users?cursor=eyJpZCI6MTIzfQ&limit=20
{
"data": [...],
"meta": {
"has_more": true,
"next_cursor": "eyJpZCI6MTQzfQ"
},
"links": {
"next": "/users?cursor=eyJpZCI6MTQzfQ&limit=20"
}
}
Filtering & Sorting
# â
Query parameter filtering
GET /users?status=active
GET /users?role=admin&status=active
GET /users?created_after=2024-01-01
# â
Sorting
GET /users?sort=created_at # Ascending (default)
GET /users?sort=-created_at # Descending (prefix with -)
GET /users?sort=last_name,-created_at # Multiple fields
# â
Field selection (sparse fieldsets)
GET /users?fields=id,name,email
GET /users/123?fields=id,name,orders
# â
Search
GET /users?q=john
GET /users?search=john@example
Consistent Response Structure
// â
Single resource
GET /users/123
{
"data": {
"id": "123",
"type": "user",
"attributes": {
"name": "John Doe",
"email": "john@example.com",
"created_at": "2024-01-15T10:30:00Z"
},
"relationships": {
"orders": {
"links": {
"related": "/users/123/orders"
}
}
}
}
}
// â
Collection
GET /users
{
"data": [
{ "id": "123", "type": "user", ... },
{ "id": "124", "type": "user", ... }
],
"meta": {
"total_count": 100
},
"links": {
"self": "/users?page=1",
"next": "/users?page=2"
}
}
// â
Simpler envelope (also acceptable)
{
"user": {
"id": "123",
"name": "John Doe"
}
}
{
"users": [...],
"pagination": {...}
}
Versioning
# â
URL path versioning (recommended - explicit)
GET /api/v1/users
GET /api/v2/users
# â
Header versioning
GET /api/users
Accept: application/vnd.myapi.v2+json
# â
Query parameter (simple, but less clean)
GET /api/users?version=2
Rate Limiting
# â
Include rate limit headers
HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 998
X-RateLimit-Reset: 1640995200
# â
Rate limited response
HTTP/1.1 429 Too Many Requests
Retry-After: 60
{
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests. Please retry after 60 seconds.",
"retry_after": 60
}
}
Actions on Resources
# For non-CRUD actions, use sub-resources or actions
# â
Sub-resource style
POST /users/123/activate
POST /orders/456/cancel
POST /posts/789/publish
# â
Or controller-style for complex operations
POST /auth/login
POST /auth/logout
POST /auth/refresh
POST /password/reset
POST /password/reset/confirm
Request Validation
// â
Validate and return all errors at once
POST /users
{
"email": "invalid",
"password": "short"
}
// Response: 422 Unprocessable Entity
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"details": [
{
"field": "email",
"code": "INVALID_FORMAT",
"message": "Must be a valid email address"
},
{
"field": "password",
"code": "TOO_SHORT",
"message": "Must be at least 8 characters",
"meta": {
"min_length": 8,
"actual_length": 5
}
}
]
}
}
HATEOAS (Hypermedia)
// â
Include links for discoverability
{
"data": {
"id": "123",
"status": "pending",
"total": 99.99
},
"links": {
"self": "/orders/123",
"cancel": "/orders/123/cancel",
"pay": "/orders/123/pay",
"items": "/orders/123/items"
},
"actions": {
"cancel": {
"method": "POST",
"href": "/orders/123/cancel"
},
"pay": {
"method": "POST",
"href": "/orders/123/pay",
"fields": [
{ "name": "payment_method", "type": "string", "required": true }
]
}
}
}
Bulk Operations
// â
Bulk create
POST /users/bulk
{
"users": [
{ "name": "User 1", "email": "user1@example.com" },
{ "name": "User 2", "email": "user2@example.com" }
]
}
// Response with partial success
{
"data": {
"succeeded": [
{ "id": "123", "name": "User 1" }
],
"failed": [
{
"index": 1,
"error": {
"code": "DUPLICATE_EMAIL",
"message": "Email already exists"
}
}
]
},
"meta": {
"total": 2,
"succeeded": 1,
"failed": 1
}
}
Output Format
When auditing APIs, output findings in this format:
endpoint - [category] Description of issue
Example:
GET /getUsers - [rest] Use noun '/users' instead of verb '/getUsers'
POST /users - [error] Missing validation error details in 400 response
GET /users - [page] Missing pagination metadata in list response
How to Use
Read individual rule files for detailed explanations:
rules/rest-http-methods.md
rules/error-consistent-format.md
rules/page-cursor-based.md