agentleFS
omspradippatilomspradippatil/Claude-Skills/.agents/skills/api-architecture/SKILL.md

api-architecture

Skill3 starsChanged 10 days agoMITView on GitHub

Activate this skill when designing REST or GraphQL APIs, Node.js or Python backends, microservices, authentication middleware, or caching layers. Use when defining API contracts, reviewing endpoint security, or designing data validation and error schemas.

We split this skill into the rules it gives an agent

20 rules. About 0 are common, 13 are distinctive, and 7 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈13

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 7

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Before writing any code, define the contract:

    line 30
  2. Distinctive:

    Start with an OpenAPI spec or GraphQL schema — code follows the contract, not vice versa.

    line 34
  3. Very specific:

    Use a schema validation library: Zod (TypeScript), Pydantic (Python), Joi (Node.js), express-validator.

    line 54
  4. Distinctive:

    Follow single responsibility: each endpoint manages one resource type.

    line 109
  5. Distinctive:

    Never expose internal database IDs directly if they're sequential integers — use UUIDs or nanoid.

    line 111
  6. Distinctive:

    Never make breaking changes to an existing version.

    line 122
  7. Very specific:

    Add Deprecation and Sunset response headers for deprecated endpoints.

    line 124
  8. Very specific:

    Structured logging: Use JSON logs (not printf-style).

    line 146
  9. Very specific:

    Distributed tracing: Add X-Request-ID or X-Trace-ID headers.

    line 148
  10. Distinctive:

    Unit tests: Test validation logic, business rules, transformation functions in isolation.

    line 156
  11. Distinctive:

    Integration tests: Test the full request-response cycle including database interactions.

    line 157
  12. Distinctive:

    Contract tests: If you have multiple consumers, use Pact or similar to verify both sides honor the contract.

    line 158
  13. Distinctive:

    Load tests: Before launch, test at expected peak + 3× spike with k6, Artillery, or Locust.

    line 159
  14. Distinctive:

    Test all error paths — not just happy paths.

    line 160
  15. Very specific:

    Use nouns, not verbs: /articles not /getArticles.

    line 177
  16. Very specific:

    Use plural nouns: /users not /user.

    line 178
  17. Distinctive:

    Always paginate list endpoints.

    line 182
  18. Distinctive:

    Every list resolver that fetches related data will trigger N additional queries.

    line 218
  19. Very specific:

    Use graphql-depth-limit (max depth 5–7) and graphql-query-complexity.

    line 229
  20. Distinctive:

    Use persisted queries (allowlist of known query hashes) for maximum security.

    line 234

≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

API Architecture Skill


When to Activate

  • Designing new REST or GraphQL APIs from scratch
  • Reviewing or refactoring existing API structure
  • Auth/authz middleware design (JWT, OAuth, API keys, sessions)
  • Input validation and error response schemas
  • Rate limiting and throttling strategy
  • API versioning decisions
  • Microservice communication patterns
  • OpenAPI/Swagger spec generation
  • Logging, tracing, and observability setup

Design Process (Step-by-Step)

Step 1 — Define the API Contract

Before writing any code, define the contract:

  • Who are the consumers? (web frontend, mobile app, third-party, internal services)
  • What resource model does the API expose?
  • What actions are needed? Map to HTTP methods (REST) or operations (GraphQL).
  • Start with an OpenAPI spec or GraphQL schema — code follows the contract, not vice versa.

API-first benefits: Enables parallel frontend/backend development, auto-generates client SDKs, serves as living documentation.

Step 2 — Auth & AuthZ Design

Authentication options:

  • JWT (Bearer token): Stateless, scalable. Use for SPAs, mobile apps. Require short expiry (15min access, 7d refresh). Algorithm must be pinned (RS256 for asymmetric, HS256 with secure secret minimum 256-bit).
  • Session cookies: Stateful, server-managed. Good for SSR apps. Require HttpOnly; Secure; SameSite=Strict.
  • API keys: For server-to-server. Hash stored server-side (never plaintext), prefix-based routing (sk_live_...), rotatable.
  • OAuth 2.0 / OIDC: For delegated access. Use PKCE for all public clients.

Authorization patterns:

  • RBAC (Role-Based Access Control): roles → permissions → resources. Simple to understand and audit.
  • ABAC (Attribute-Based Access Control): evaluate policies based on resource/user/environment attributes. More flexible, more complex.
  • Ownership check: always verify resource.userId === requestingUser.id before returning or modifying.
  • Fail closed: if the auth check fails or is ambiguous, deny access.

Step 3 — Input Validation & Error Schema

Validation rules:

  • Validate at the API boundary — don't trust any input.
  • Use a schema validation library: Zod (TypeScript), Pydantic (Python), Joi (Node.js), express-validator.
  • Validate: types, ranges, lengths, formats (email, URL, UUID), presence of required fields.
  • Sanitize: strip unexpected fields (mass assignment prevention), normalize strings.

Standard error response schema (use consistently across all endpoints):

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      {
        "field": "email",
        "message": "Must be a valid email address"
      }
    ],
    "requestId": "req_abc123",
    "timestamp": "2024-01-15T10:30:00Z"
  }
}

HTTP status codes to use:

CodeWhen to use
200 OKSuccessful GET, PUT, PATCH
201 CreatedSuccessful POST that creates a resource
204 No ContentSuccessful DELETE or action with no body
400 Bad RequestInvalid input, validation failure
401 UnauthorizedNot authenticated
403 ForbiddenAuthenticated but not authorized
404 Not FoundResource does not exist
409 ConflictDuplicate resource, state conflict
422 Unprocessable EntitySemantically invalid (valid format, invalid business logic)
429 Too Many RequestsRate limit exceeded
500 Internal Server ErrorUnexpected server error
503 Service UnavailableDownstream dependency failure

Step 4 — Rate Limiting

  • Apply at the API gateway or middleware level — not per-endpoint unless specific needs.
  • Strategies:
    • Fixed window: Simple, but susceptible to burst at window boundary.
    • Sliding window: More accurate, prevents boundary bursts. Preferred.
    • Token bucket: Allows controlled bursting, good for APIs that need flexibility.
  • Limits by: IP (unauthenticated), user ID (authenticated), API key.
  • Return 429 Too Many Requests with headers:
    Retry-After: 60
    X-RateLimit-Limit: 100
    X-RateLimit-Remaining: 0
    X-RateLimit-Reset: 1705312200
  • Back rate limits with Redis or an in-memory store — not a database.

Step 5 — Data Model Design

  • Follow single responsibility: each endpoint manages one resource type.
  • Separate your API resource model from your database model — use a DTO (Data Transfer Object) layer.
  • Never expose internal database IDs directly if they're sequential integers — use UUIDs or nanoid.
  • Soft delete preferred for user-facing data (add deleted_at column) — allows recovery and audit trails.
  • Timestamps: all resources should have created_at, updated_at.

Step 6 — API Versioning

Strategies (pick one and be consistent):

  • URL versioning: /api/v1/users — Most explicit, easiest to route. Recommended for public APIs.
  • Header versioning: Accept: application/vnd.api+json;version=1 — Cleaner URLs, harder to test in browser.
  • Query param: /api/users?version=1 — Simple but can conflict with other params.

Rules:

  • Never make breaking changes to an existing version.
  • Deprecation policy: announce → deprecation header → sunset date → removal.
  • Add Deprecation and Sunset response headers for deprecated endpoints.
  • Support at least N-1 versions at any time.

Step 7 — Logging & Observability

What to log on every request:

{
  "requestId": "req_abc123",
  "method": "POST",
  "path": "/api/v1/orders",
  "statusCode": 201,
  "durationMs": 45,
  "userId": "usr_xyz",
  "userAgent": "Mozilla/5.0...",
  "ip": "203.0.113.1"
}

What NOT to log:

  • Passwords, tokens, API keys, card numbers, SSNs — mask or omit.
  • Full request bodies (may contain PII) — log field names only, not values for sensitive fields.

Structured logging: Use JSON logs (not printf-style). Tools: Winston, Pino (Node.js), structlog (Python).

Distributed tracing: Add X-Request-ID or X-Trace-ID headers. Pass through all service calls. Log the trace ID at every hop.

Metrics to instrument:

  • Request rate, error rate, latency (p50/p95/p99) — the RED method.
  • Saturation (queue depth, connection pool usage).
  • Business metrics (orders created, payments processed).

Step 8 — Testing Strategy

  • Unit tests: Test validation logic, business rules, transformation functions in isolation.
  • Integration tests: Test the full request-response cycle including database interactions. Use a test database, not mocks.
  • Contract tests: If you have multiple consumers, use Pact or similar to verify both sides honor the contract.
  • Load tests: Before launch, test at expected peak + 3× spike with k6, Artillery, or Locust.
  • Test all error paths — not just happy paths.

REST Best Practices

Resource Naming

GET    /api/v1/articles          → List articles
POST   /api/v1/articles          → Create article
GET    /api/v1/articles/:id      → Get one article
PATCH  /api/v1/articles/:id      → Update article (partial)
PUT    /api/v1/articles/:id      → Replace article (full)
DELETE /api/v1/articles/:id      → Delete article

GET    /api/v1/articles/:id/comments  → Nested resource
  • Use nouns, not verbs: /articles not /getArticles.
  • Use plural nouns: /users not /user.
  • Kebab-case for multi-word: /blog-posts not /blogPosts.

Pagination

Always paginate list endpoints. Use cursor-based pagination for large/real-time datasets:

{
  "data": [...],
  "pagination": {
    "cursor": "eyJpZCI6MTAwfQ==",
    "hasMore": true,
    "total": 1542
  }
}

Offset pagination for simple use cases:

{
  "data": [...],
  "pagination": {
    "page": 2,
    "perPage": 25,
    "total": 1542,
    "totalPages": 62
  }
}

Filtering & Sorting

GET /api/v1/articles?status=published&author=user_123
GET /api/v1/articles?sort=created_at&order=desc
GET /api/v1/articles?fields=id,title,created_at   (sparse fieldsets)

GraphQL Considerations

N+1 Problem

  • Every list resolver that fetches related data will trigger N additional queries.
  • Solution: use DataLoader to batch and cache per-request.
const userLoader = new DataLoader(async (ids) => {
  const users = await db.users.findMany({ where: { id: { in: ids } } });
  return ids.map(id => users.find(u => u.id === id));
});

Query Depth & Complexity Limits

  • Malicious or accidental queries can deeply nest (user → posts → comments → author → posts...).
  • Use graphql-depth-limit (max depth 5–7) and graphql-query-complexity.
  • Set a timeout on query execution.

Production Hardening

  • Disable introspection in production (or restrict to authenticated users).
  • Use persisted queries (allowlist of known query hashes) for maximum security.
  • Rate limit by query complexity points, not just request count.
  • Implement field-level authorization in resolvers, not just at the top level.

Security Checklist

  • All inputs validated with a schema validator before processing
  • No SQL string interpolation — parameterized queries or ORM only
  • CORS policy explicit: origin allowlist, not * for credentialed requests
  • JWT: algorithm pinned, expiry set, refresh token rotation implemented
  • Sensitive fields (password, token) stripped from response objects
  • Rate limiting on all public endpoints
  • Error messages don't leak internal details (stack traces, SQL, file paths)
  • API keys hashed in database, never stored plaintext
  • Auth check on every protected route — no security by obscurity
  • Mass assignment prevented — explicit allowlist of accepted fields

OpenAPI Spec Template

openapi: 3.1.0
info:
  title: My API
  version: 1.0.0
  description: API description
servers:
  - url: https://api.example.com/v1
    description: Production
  - url: https://staging-api.example.com/v1
    description: Staging

security:
  - BearerAuth: []

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

  schemas:
    Error:
      type: object
      required: [error]
      properties:
        error:
          type: object
          required: [code, message]
          properties:
            code: { type: string }
            message: { type: string }
            requestId: { type: string }

paths:
  /articles:
    get:
      summary: List articles
      parameters:
        - in: query
          name: cursor
          schema: { type: string }
        - in: query
          name: limit
          schema: { type: integer, minimum: 1, maximum: 100, default: 25 }
      responses:
        '200':
          description: Success
        '401':
          description: Unauthorized
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Error' }

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.