Agent Skills: API Architecture Skill

Production-grade API architecture skill for REST, gRPC, GraphQL design, versioning, and security patterns

RESTgRPCGraphQLAPI-designapi-versioning
architectureID: pluginagentmarketplace/custom-plugin-system-design/api-architecture

Skill Files

Browse the full folder contents for api-architecture.

Download Skill

Loading file tree…

skills/api-architecture/SKILL.md

Skill Metadata

Name
api-architecture
Description
Production-grade API architecture skill for REST, gRPC, GraphQL design, versioning, and security patterns

API Architecture Skill

Purpose: Atomic skill for API design with comprehensive validation, error handling, and security patterns.

Skill Identity

| Attribute | Value | |-----------|-------| | Scope | REST, gRPC, GraphQL Design | | Responsibility | Single: API contract and protocol design | | Invocation | Skill("api-architecture") |

Parameter Schema

Input Validation

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 Schema

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 }

Core Patterns

REST Design Principles

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

gRPC Patterns

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

GraphQL Patterns

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 Logic

Client Retry Configuration

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

Logging & Observability

Log Format

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

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]

Troubleshooting

Common Issues

| 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 |

Debug Checklist

□ 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?

Unit Test Templates

API Validation Tests

# 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"}

Status Code Tests

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 History

| Version | Date | Changes | |---------|------|---------| | 2.0.0 | 2025-01 | Production-grade rewrite with security patterns | | 1.0.0 | 2024-12 | Initial release |