Backend Patterns for API Design: 7 Essential Patterns from Everything Claude Code

Everything Claude Code recommends seven core backend patterns—RESTful API structure, repository abstraction, service layer encapsulation, middleware composition, centralized error handling, JWT-based authentication, and token-bucket rate limiting—to build scalable, maintainable, and secure APIs.

Everything Claude Code (ECC) is an open-source knowledge base that documents opinionated backend patterns for API design in modern web applications. These patterns, defined in skills/backend-patterns/SKILL.md, provide a layered architecture approach that separates concerns between HTTP handling, business logic, and data access.

RESTful API Structure

ECC advocates for resource-based URL design with standard HTTP verbs. This pattern standardizes endpoint URLs across your application.

Endpoints follow the pattern:

  • GET /api/markets — List resources
  • POST /api/markets — Create resource
  • GET /api/markets/:id — Retrieve specific resource
  • PUT /api/markets/:id — Update resource
  • DELETE /api/markets/:id — Delete resource

Query parameters handle filtering, sorting, and pagination rather than implementing these as separate endpoints【23†L23-L36】.

Repository Pattern

The repository pattern isolates data-access logic behind an abstract interface, making it easy to swap storage implementations without affecting business logic.

ECC defines this through:

  • An interface MarketRepository with methods like findAll, findById, create, update, and delete
  • A concrete implementation SupabaseMarketRepository that interacts with Supabase【38†L38-L70】

This abstraction allows teams to switch from Supabase to Prisma or another database by implementing the same interface, without touching service layer code.

// src/repositories/SupabaseMarketRepository.ts
import { supabase } from '@/lib/supabase';

export class SupabaseMarketRepository implements MarketRepository {
  async findAll(filters?: MarketFilters): Promise<Market[]> {
    let query = supabase.from('markets').select('*');

    if (filters?.status) query = query.eq('status', filters.status);
    if (filters?.limit) query = query.limit(filters.limit);

    const { data, error } = await query;
    if (error) throw new Error(error.message);
    return data ?? [];
  }

  // …other CRUD methods (findById, create, update, delete)…
}

Service Layer Pattern

The service layer keeps business rules separate from data access, enabling reuse and unit testing. Services orchestrate repositories and implement domain logic.

As implemented in ECC, class MarketService receives a MarketRepository via dependency injection and implements higher-level operations such as searchMarkets. This layer coordinates AI embedding generation, vector search, and repository retrieval without exposing these details to the HTTP layer【72†L72-L99】.

// src/services/MarketService.ts
import { MarketRepository } from '@/repositories/MarketRepository';
import { generateEmbedding } from '@/lib/ai';

export class MarketService {
  constructor(private repo: MarketRepository) {}

  async searchMarkets(query: string, limit = 10) {
    const embedding = await generateEmbedding(query);
    const ids = await this.vectorSearch(embedding, limit); // custom vector search
    const markets = await this.repo.findByIds(ids);
    // Additional business rules could be applied here
    return markets;
  }

  private async vectorSearch(embedding: number[], limit: number): Promise<string[]> {
    // Placeholder for real vector search logic
    return [];
  }
}

Middleware Pattern

Middleware centralizes cross-cutting concerns such as authentication, logging, and rate-limiting before requests reach handlers.

ECC's withAuth wrapper demonstrates this pattern:

  • Validates JWT tokens from the Authorization header
  • Injects req.user into the request object
  • Throws ApiError(401) for missing or invalid tokens【101†L101-L127】

This keeps route handlers clean and focused on business logic rather than authentication checks.

// src/lib/middleware.ts
import { NextApiHandler, NextResponse } from 'next/server';
import { verifyToken } from '@/lib/auth';
import { ApiError } from '@/lib/error';

export function withAuth(handler: NextApiHandler) {
  return async (req, res) => {
    const token = req.headers.get('authorization')?.replace('Bearer ', '');
    if (!token) throw new ApiError(401, 'Unauthorized');

    try {
      const user = await verifyToken(token);
      (req as any).user = user; // attach user to request
      return handler(req, res);
    } catch {
      throw new ApiError(401, 'Invalid token');
    }
  };
}

Error-Handling Pattern

Centralized error handling provides a single place to translate exceptions into consistent API responses.

ECC's errorHandler distinguishes between:

  • ApiError instances (business logic errors with specific status codes)
  • ZodError instances (validation failures)
  • Unexpected errors (generic 500 responses)【64†L64-L87】

This pattern eliminates duplicated try/catch blocks across endpoints and ensures uniform error serialization.

Authentication and Authorization

ECC implements JWT-based authentication with role-based access control (RBAC).

Key components include:

  • verifyToken — Validates JWT signatures and expiration
  • requireAuth — Ensures authenticated sessions
  • hasPermission — Checks user roles against required permissions
  • requirePermission — Higher-order function that wraps handlers with permission checks【46†L46-L78】

This stack provides a complete, reusable authentication layer that integrates with the middleware pattern.

Rate-Limiting Pattern

To protect APIs from abuse, ECC recommends token-bucket rate limiting.

The RateLimiter class tracks request timestamps per IP or user key:

  • Stores timestamps in an in-memory Map
  • Filters entries outside the time window
  • Returns 429 Too Many Requests when limits are exceeded【32†L32-L44】

This pattern prevents resource exhaustion and ensures fair usage across clients.

// src/lib/rateLimiter.ts
export class RateLimiter {
  private store = new Map<string, number[]>();

  async isAllowed(key: string, max: number, windowMs: number): Promise<boolean> {
    const now = Date.now();
    const timestamps = this.store.get(key) ?? [];

    const recent = timestamps.filter(t => now - t < windowMs);
    if (recent.length >= max) return false;

    recent.push(now);
    this.store.set(key, recent);
    return true;
  }
}

Summary

Everything Claude Code recommends these seven backend patterns for API design:

  • RESTful API Structure — Resource-based URLs with standard HTTP verbs and query parameters for filtering
  • Repository Pattern — Abstract interfaces that isolate data access and enable storage implementation swaps
  • Service Layer Pattern — Business logic encapsulation that coordinates repositories and external services
  • Middleware Pattern — Cross-cutting concern composition (auth, logging) that keeps handlers clean
  • Error-Handling Pattern — Centralized exception translation into consistent API responses
  • Authentication & Authorization — JWT-based identity verification with role-based permission checking
  • Rate-Limiting — Token-bucket throttling to prevent API abuse

These patterns form a layered architecture that separates HTTP handling, business logic, and data persistence, resulting in testable, maintainable, and secure APIs.

Frequently Asked Questions

What is the repository pattern and why does Everything Claude Code recommend it?

The repository pattern abstracts data access behind an interface, allowing business logic to remain agnostic of storage implementations. Everything Claude Code recommends this pattern because it enables teams to swap databases (e.g., from Supabase to PostgreSQL) without modifying service layer code, as demonstrated by the MarketRepository interface and SupabaseMarketRepository implementation.

How does Everything Claude Code handle authentication in API middleware?

Everything Claude Code implements authentication through the withAuth middleware wrapper, which validates JWT tokens from the Authorization header and injects the decoded user object into the request. This pattern centralizes authentication logic, allowing route handlers to access req.user directly without duplicating token verification code across endpoints.

Where should business logic reside according to Everything Claude Code patterns?

According to Everything Claude Code, business logic should reside in the service layer, specifically in classes like MarketService that receive repository instances via dependency injection. This layer coordinates data access, external API calls (such as AI embedding generation), and domain rules, keeping controllers thin and focused on HTTP concerns.

What error handling approach does Everything Claude Code recommend for APIs?

Everything Claude Code recommends a centralized error-handling pattern using an errorHandler function that distinguishes between ApiError instances (business logic errors), ZodError instances (validation failures), and unexpected errors. This approach eliminates duplicated try/catch blocks across endpoints and ensures consistent HTTP status codes and JSON error responses.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →