15 minlesson

Real-World Chain Examples

Real-World Chain Examples

HTTP Request Pipeline

typescript
1interface HttpContext {
2 request: Request;
3 response: Response;
4 user?: User;
5 data: Map<string, any>;
6}
7
8abstract class HttpMiddleware {
9 protected next: HttpMiddleware | null = null;
10
11 setNext(middleware: HttpMiddleware): HttpMiddleware {
12 this.next = middleware;
13 return middleware;
14 }
15
16 abstract handle(context: HttpContext): Promise<void>;
17
18 protected async callNext(context: HttpContext): Promise<void> {
19 if (this.next) {
20 await this.next.handle(context);
21 }
22 }
23}
24
25class AuthenticationMiddleware extends HttpMiddleware {
26 async handle(context: HttpContext): Promise<void> {
27 const token = context.request.headers.get('Authorization');
28
29 if (token) {
30 context.user = await this.validateToken(token);
31 }
32
33 await this.callNext(context);
34 }
35}
36
37class AuthorizationMiddleware extends HttpMiddleware {
38 async handle(context: HttpContext): Promise<void> {
39 if (!context.user) {
40 context.response.status = 401;
41 return;
42 }
43
44 if (!this.hasPermission(context.user, context.request.path)) {
45 context.response.status = 403;
46 return;
47 }
48
49 await this.callNext(context);
50 }
51}
52
53class RateLimitMiddleware extends HttpMiddleware {
54 async handle(context: HttpContext): Promise<void> {
55 const key = context.user?.id ?? context.request.ip;
56
57 if (await this.isRateLimited(key)) {
58 context.response.status = 429;
59 return;
60 }
61
62 await this.callNext(context);
63 }
64}

Support Ticket Escalation

typescript
1interface Ticket {
2 id: string;
3 priority: 'low' | 'medium' | 'high' | 'critical';
4 category: string;
5 description: string;
6 assignee?: string;
7}
8
9abstract class SupportHandler {
10 protected next: SupportHandler | null = null;
11
12 setNext(handler: SupportHandler): SupportHandler {
13 this.next = handler;
14 return handler;
15 }
16
17 handle(ticket: Ticket): Ticket {
18 if (this.canHandle(ticket)) {
19 return this.process(ticket);
20 }
21
22 if (this.next) {
23 return this.next.handle(ticket);
24 }
25
26 return { ...ticket, assignee: 'unassigned' };
27 }
28
29 protected abstract canHandle(ticket: Ticket): boolean;
30 protected abstract process(ticket: Ticket): Ticket;
31}
32
33class Tier1Support extends SupportHandler {
34 protected canHandle(ticket: Ticket): boolean {
35 return ticket.priority === 'low' &&
36 ['billing', 'account'].includes(ticket.category);
37 }
38
39 protected process(ticket: Ticket): Ticket {
40 return { ...ticket, assignee: 'tier1-team' };
41 }
42}
43
44class Tier2Support extends SupportHandler {
45 protected canHandle(ticket: Ticket): boolean {
46 return ticket.priority === 'medium' ||
47 ticket.category === 'technical';
48 }
49
50 protected process(ticket: Ticket): Ticket {
51 return { ...ticket, assignee: 'tier2-team' };
52 }
53}
54
55class EngineeringSupport extends SupportHandler {
56 protected canHandle(ticket: Ticket): boolean {
57 return ticket.priority === 'critical' ||
58 ticket.category === 'bug';
59 }
60
61 protected process(ticket: Ticket): Ticket {
62 return { ...ticket, assignee: 'engineering-team' };
63 }
64}

Discount Calculator

typescript
1interface Order {
2 items: OrderItem[];
3 customer: Customer;
4 subtotal: number;
5 discounts: Discount[];
6}
7
8abstract class DiscountHandler {
9 protected next: DiscountHandler | null = null;
10
11 setNext(handler: DiscountHandler): DiscountHandler {
12 this.next = handler;
13 return handler;
14 }
15
16 apply(order: Order): Order {
17 const discount = this.calculate(order);
18
19 if (discount) {
20 order = {
21 ...order,
22 discounts: [...order.discounts, discount]
23 };
24 }
25
26 if (this.next) {
27 return this.next.apply(order);
28 }
29
30 return order;
31 }
32
33 protected abstract calculate(order: Order): Discount | null;
34}
35
36class LoyaltyDiscount extends DiscountHandler {
37 protected calculate(order: Order): Discount | null {
38 if (order.customer.loyaltyTier === 'gold') {
39 return { type: 'loyalty', amount: order.subtotal * 0.1, description: '10% Gold Member' };
40 }
41 if (order.customer.loyaltyTier === 'silver') {
42 return { type: 'loyalty', amount: order.subtotal * 0.05, description: '5% Silver Member' };
43 }
44 return null;
45 }
46}
47
48class VolumeDiscount extends DiscountHandler {
49 protected calculate(order: Order): Discount | null {
50 if (order.subtotal >= 500) {
51 return { type: 'volume', amount: order.subtotal * 0.15, description: '15% Volume Discount' };
52 }
53 if (order.subtotal >= 200) {
54 return { type: 'volume', amount: order.subtotal * 0.08, description: '8% Volume Discount' };
55 }
56 return null;
57 }
58}
59
60class PromotionalDiscount extends DiscountHandler {
61 constructor(private activeCodes: Map<string, number>) {
62 super();
63 }
64
65 protected calculate(order: Order): Discount | null {
66 const code = order.customer.promoCode;
67 if (code && this.activeCodes.has(code)) {
68 const percent = this.activeCodes.get(code)!;
69 return { type: 'promo', amount: order.subtotal * percent, description: `${percent * 100}% Promo` };
70 }
71 return null;
72 }
73}

Testing Chains

typescript
1describe('DiscountChain', () => {
2 let chain: DiscountHandler;
3
4 beforeEach(() => {
5 const loyalty = new LoyaltyDiscount();
6 const volume = new VolumeDiscount();
7 const promo = new PromotionalDiscount(new Map([['SAVE10', 0.10]]));
8
9 loyalty.setNext(volume).setNext(promo);
10 chain = loyalty;
11 });
12
13 it('applies all applicable discounts', () => {
14 const order = {
15 subtotal: 500,
16 customer: { loyaltyTier: 'gold', promoCode: 'SAVE10' },
17 discounts: []
18 };
19
20 const result = chain.apply(order);
21
22 expect(result.discounts).toHaveLength(3); // loyalty + volume + promo
23 });
24
25 it('skips inapplicable discounts', () => {
26 const order = {
27 subtotal: 50,
28 customer: { loyaltyTier: 'none' },
29 discounts: []
30 };
31
32 const result = chain.apply(order);
33
34 expect(result.discounts).toHaveLength(0);
35 });
36});

Summary

Chain of Responsibility is common in:

  • HTTP middleware pipelines
  • Support ticket routing
  • Discount/pricing calculations
  • Validation workflows
  • Event handling systems