← Back to scenarios
ScenarioCatalog DB

Notification routing chain

Route a message through preference checks, channel selection, and fallback handlers.

Problem

A notification system must evaluate recipient preferences, select an available delivery channel, and fall back when necessary without coupling message producers to all routing and delivery rules.

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