behavioral

Chain of Responsibility

Pass requests along a chain of handlers until one of them handles the request or the request reaches the end of the chain.

Problem

behavioral

A request must pass through multiple possible handlers, but the sender should not need to know which handler will process it.

Integration notes

Chain of Responsibility is useful for validation pipelines, support routing, approval flows, and any system where requests may be processed by different handlers in sequence.

Tradeoffs

  • Requests can become harder to trace because control flows through multiple handlers.
  • A long chain may add overhead if many handlers are checked on every request.
  • It keeps handler logic isolated and easier to extend.

Languages

typescript, java, python, angular, react, react-native, csharp, dotnet

Platforms

frontend, backend, integration

Variants

backend

Validation chain

typescript

Process inputs through a sequence of validation handlers that can approve or reject the request.

Intent: Keep validation rules isolated and composable.

Problem: Validation becomes hard to change when all rules are packed into one function.

Solution: Use a chain so each validator can inspect the request and decide whether processing should continue.

Dependencies

chain of responsibility

Related variants

cor-escalation-chaincor-workflow-approval-chain

Examples

chain-of-responsibility

Good for password checks, form validation, and request sanitization.

Scenarios

Request middleware chain

A web request flows through logging, auth, rate limiting, and transformation handlers.

Context: An application needs a predictable sequence of middleware before a controller handles the request.

Problem: Embedding cross-cutting concerns directly in controllers creates duplication and coupling.

Solution: Use Chain of Responsibility to process the request through reusable middleware handlers.

frontend

Language examples

Core languages

Frameworks and libraries

Request middleware chaintypescript

A middleware chain is a practical Chain of Responsibility form for web requests and cross-cutting concerns.

TypeScript
type Request = { path: string; user?: string };

type Middleware = {
  setNext(next: Middleware): Middleware;
  handle(request: Request): Request;
};

abstract class BaseMiddleware implements Middleware {
  protected next: Middleware | null = null;

  setNext(next: Middleware) {
    this.next = next;
    return next;
  }

  handle(request: Request): Request {
    return this.next ? this.next.handle(request) : request;
  }
}

class LoggingMiddleware extends BaseMiddleware {
  handle(request: Request) {
    console.log("request", request.path);
    return super.handle(request);
  }
}

class AuthMiddleware extends BaseMiddleware {
  handle(request: Request) {
    if (!request.user) throw new Error("Unauthorized");
    return super.handle(request);
  }
}

class RateLimitMiddleware extends BaseMiddleware {
  handle(request: Request) {
    return super.handle(request);
  }
}

const chain = new LoggingMiddleware();
chain.setNext(new AuthMiddleware()).setNext(new RateLimitMiddleware());

Real-world examples

  • Validation pipelines: Form inputs often pass through multiple validation rules before a submission is accepted.
  • Support routing: Help desks frequently forward tickets through escalating tiers until someone can resolve the issue.
  • Approval workflows: Business requests often move through managers, finance, and executives until the appropriate approver signs off.