Production-grade API architecture skill for REST, gRPC, GraphQL design, versioning, and security patterns
Designs production-ready REST, gRPC, and GraphQL APIs with security, versioning, and validation patterns. Used when you need to create API contracts, endpoints, or OpenAPI specs from resource definitions.
/plugin marketplace add pluginagentmarketplace/custom-plugin-system-design/plugin install custom-plugin-system-design@pluginagentmarketplace-system-designThis skill inherits all available tools. When active, it can use any tool Claude has access to.
assets/config.yamlassets/schema.jsonreferences/GUIDE.mdreferences/PATTERNS.mdscripts/validate.pyPurpose: Atomic skill for API design with comprehensive validation, error handling, and security patterns.
| Attribute | Value |
|---|---|
| Scope | REST, gRPC, GraphQL Design |
| Responsibility | Single: API contract and protocol design |
| Invocation | Skill("api-architecture") |
parameters:
api_context:
type: object
required: true
properties:
protocol:
type: string
enum: [REST, gRPC, GraphQL, hybrid]
required: true
resources:
type: array
items:
type: object
properties:
name: { type: string, pattern: "^[a-z][a-z0-9-]*$" }
operations: { type: array, items: { type: string } }
minItems: 1
consumers:
type: array
items:
type: string
enum: [web, mobile, third_party, internal, iot]
security:
type: object
properties:
auth_method: { type: string, enum: [oauth2, api_key, jwt, mtls] }
rate_limiting: { type: boolean, default: true }
constraints:
type: object
properties:
max_latency_ms: { type: integer, minimum: 1 }
backward_compatible: { type: boolean, default: true }
validation_rules:
- name: "resource_naming"
rule: "resources[*].name matches /^[a-z][a-z0-9-]*$/"
error: "Resource names must be lowercase with hyphens"
- name: "public_api_security"
rule: "consumers includes 'third_party' implies auth_method is set"
error: "Public APIs require authentication"
output:
type: object
properties:
endpoints:
type: array
items:
type: object
properties:
method: { type: string }
path: { type: string }
request_schema: { type: object }
response_schema: { type: object }
status_codes: { type: array }
openapi_spec:
type: string
format: yaml
security_config:
type: object
properties:
auth: { type: object }
rate_limits: { type: object }
cors: { type: object }
Resource Naming:
├── Nouns, plural: /users, /orders
├── Hierarchical: /users/{id}/orders
├── Actions as sub-resources: /orders/{id}/cancel
├── Query params for filtering: ?status=active
└── Kebab-case: /user-profiles
HTTP Methods:
├── GET → Read (idempotent, cacheable)
├── POST → Create (not idempotent)
├── PUT → Replace (idempotent)
├── PATCH → Update partial (idempotent)
├── DELETE → Remove (idempotent)
├── HEAD → Metadata only
└── OPTIONS → CORS preflight
Status Codes:
├── 200 OK: Successful GET/PUT/PATCH
├── 201 Created: Successful POST (with Location header)
├── 204 No Content: Successful DELETE
├── 400 Bad Request: Validation error
├── 401 Unauthorized: Not authenticated
├── 403 Forbidden: Not authorized
├── 404 Not Found: Resource missing
├── 409 Conflict: State conflict
├── 422 Unprocessable: Semantic error
├── 429 Too Many Requests: Rate limited
├── 500 Internal Error: Server bug
├── 502 Bad Gateway: Upstream error
├── 503 Unavailable: Maintenance
└── 504 Gateway Timeout: Upstream timeout
Service Types:
├── Unary: request → response
├── Server Streaming: request → stream<response>
├── Client Streaming: stream<request> → response
└── Bidirectional: stream<request> → stream<response>
Proto Best Practices:
├── Use proto3
├── Package: company.service.v1
├── Reserve deleted field numbers
├── Use well-known types
└── Backward compatible changes only
Schema Design:
├── Types: Clear domain modeling
├── Queries: Read operations
├── Mutations: Write operations
├── Subscriptions: Real-time
└── Input types: Separate from output
Security:
├── Query depth limiting
├── Complexity analysis
├── Field-level authorization
├── Persisted queries
└── Rate limiting by complexity
retry_config:
http_client:
max_attempts: 3
initial_delay_ms: 100
max_delay_ms: 10000
multiplier: 2.0
jitter_factor: 0.2
retryable_status_codes:
- 429 # Rate limited (use Retry-After)
- 502 # Bad gateway
- 503 # Service unavailable
- 504 # Gateway timeout
non_retryable:
- 400 # Bad request
- 401 # Unauthorized
- 403 # Forbidden
- 404 # Not found
- 409 # Conflict
- 422 # Unprocessable
idempotency:
header: "Idempotency-Key"
required_for: [POST, PATCH]
cache_ttl_seconds: 86400
log_schema:
level: { type: string }
timestamp: { type: string, format: ISO8601 }
skill: { type: string, value: "api-architecture" }
request_id: { type: string }
event:
type: string
enum:
- endpoint_designed
- schema_generated
- validation_passed
- security_configured
- rate_limit_set
context:
type: object
properties:
method: { type: string }
path: { type: string }
protocol: { type: string }
example:
level: INFO
request_id: "req_abc123"
event: endpoint_designed
context:
method: POST
path: /v1/users
protocol: REST
metrics:
- name: api_request_total
type: counter
labels: [method, path, status]
- name: api_request_duration_seconds
type: histogram
labels: [method, path]
buckets: [0.005, 0.01, 0.05, 0.1, 0.5, 1, 5]
- name: api_rate_limit_exceeded_total
type: counter
labels: [client_id, path]
- name: api_error_total
type: counter
labels: [method, path, error_code]
| Issue | Cause | Resolution |
|---|---|---|
| 400 errors | Schema mismatch | Validate against OpenAPI |
| 401 errors | Token expired | Implement refresh flow |
| 429 errors | Rate limit hit | Implement backoff, cache |
| CORS errors | Missing headers | Configure allowed origins |
| Slow response | N+1 queries | Batch, DataLoader |
□ Request matches OpenAPI spec?
□ Auth token valid and not expired?
□ Rate limit headers checked?
□ Error response format consistent?
□ Retry-After header on 429/503?
□ CORS configured for all origins?
□ Pagination implemented?
# test_api_architecture.py
def test_valid_rest_resource():
params = {
"api_context": {
"protocol": "REST",
"resources": [
{"name": "users", "operations": ["list", "get", "create", "update", "delete"]},
{"name": "orders", "operations": ["list", "get", "create"]}
],
"consumers": ["web", "mobile"],
"security": {"auth_method": "oauth2", "rate_limiting": True}
}
}
result = validate_parameters(params)
assert result.valid == True
def test_invalid_resource_naming():
params = {
"api_context": {
"protocol": "REST",
"resources": [
{"name": "Users", "operations": ["list"]} # Should be lowercase
]
}
}
result = validate_parameters(params)
assert result.valid == False
assert "lowercase" in result.errors[0]
def test_public_api_requires_auth():
params = {
"api_context": {
"protocol": "REST",
"resources": [{"name": "data", "operations": ["list"]}],
"consumers": ["third_party"]
# Missing security.auth_method
}
}
result = validate_parameters(params)
assert result.valid == False
assert "authentication" in result.errors[0]
def test_endpoint_generation():
resource = {"name": "users", "operations": ["list", "get", "create"]}
endpoints = generate_endpoints(resource)
assert endpoints[0] == {"method": "GET", "path": "/v1/users"}
assert endpoints[1] == {"method": "GET", "path": "/v1/users/{id}"}
assert endpoints[2] == {"method": "POST", "path": "/v1/users"}
def test_status_code_for_create():
operation = "create"
result = determine_status_codes(operation)
assert 201 in result.success
assert 400 in result.client_error
assert 409 in result.client_error # Conflict for duplicate
def test_rate_limit_headers():
response = generate_rate_limit_headers(
limit=1000,
remaining=998,
reset_epoch=1640995200
)
assert response["X-RateLimit-Limit"] == "1000"
assert response["X-RateLimit-Remaining"] == "998"
assert response["X-RateLimit-Reset"] == "1640995200"
def test_error_response_format():
error = generate_error_response(
code="VALIDATION_ERROR",
message="Invalid email format",
details=[{"field": "email", "reason": "must be valid email"}],
request_id="req_123"
)
assert error["error"]["code"] == "VALIDATION_ERROR"
assert error["error"]["request_id"] == "req_123"
assert len(error["error"]["details"]) == 1
| Version | Date | Changes |
|---|---|---|
| 2.0.0 | 2025-01 | Production-grade rewrite with security patterns |
| 1.0.0 | 2024-12 | Initial release |
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.