← Back to scenarios
ScenarioCatalog DB

Password validation chain

Pass a password through several validation rules before accepting it.

Problem

A system must evaluate password requirements in a defined sequence while keeping individual validation rules independent and allowing the validation pipeline to change without coupling the caller to every rule.

Related patterns

Implementations

Chain of Responsibility

TypeScriptApplication

Chain of Responsibility in TypeScript

Routes a support request through specialized handlers until one can resolve it, without coupling the requester to a specific handler.

TypeScript
type SupportRequest = {
  kind: "billing" | "technical" | "account";
  message: string;
};

abstract class SupportHandler {
  private next?: SupportHandler;

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

  handle(request: SupportRequest): void {
    if (this.canHandle(request)) {
      this.resolve(request);
      return;
    }

    if (this.next) {
      this.next.handle(request);
      return;
    }

    console.log(`No handler found for: ${request.message}`);
  }

  protected abstract canHandle(request: SupportRequest): boolean;
  protected abstract resolve(request: SupportRequest): void;
}

class BillingHandler extends SupportHandler {
  protected canHandle(request: SupportRequest) {
    return request.kind === "billing";
  }

  protected resolve(request: SupportRequest) {
    console.log(`Billing resolved: ${request.message}`);
  }
}

class TechnicalHandler extends SupportHandler {
  protected canHandle(request: SupportRequest) {
    return request.kind === "technical";
  }

  protected resolve(request: SupportRequest) {
    console.log(`Technical support resolved: ${request.message}`);
  }
}

class AccountHandler extends SupportHandler {
  protected canHandle(request: SupportRequest) {
    return request.kind === "account";
  }

  protected resolve(request: SupportRequest) {
    console.log(`Account support resolved: ${request.message}`);
  }
}

const billing = new BillingHandler();
const technical = new TechnicalHandler();
const account = new AccountHandler();

billing.setNext(technical).setNext(account);

billing.handle({
  kind: "technical",
  message: "I cannot sign in to the dashboard.",
});

Associated technologies