DEV Community

Cover image for Design Patterns Simplified: Part 10 - Chain of Responsibility Pattern (a.k.a. “Pass It Along Until Someone Handles It”)
Prateek Prabhakar
Prateek Prabhakar

Posted on • Edited on • Originally published at Medium

Design Patterns Simplified: Part 10 - Chain of Responsibility Pattern (a.k.a. “Pass It Along Until Someone Handles It”)

Chain of Responsibility Pattern belongs to the Behavioral category of design patterns.

Why? Because it’s all about decoupling who sends a request from who handles it, and allowing multiple handlers the chance to act - one at a time.

It lets you,

  • Pass a request along a chain of potential handlers
  • Let each handler decide if it can process the request
  • Stop the chain when one handler takes responsibility
  • Easily extend or modify the chain without changing existing code

It’s like creating a support system where the request keeps getting passed along until someone says, “I got this! Let me take care of it.”

Taking an example of Customer Support Ticket System

Imagine you are reaching out to customer support for some issue regarding a recent purchase. Usually, this is what a typical support hierarchy looks like.
First, a bot tries to resolve your issue.
If that doesn't work, the ticket goes to a junior agent (L1 support).
Still unresolved? It escalates to a senior agent (L2) or a supervisor (L3).

Each level tries to handle the request, and passes it on, only if it can't resolve it at their level.

That is the Chain of Responsibility in action where each level gets a chance to help, passing it on only if needed.


What is the Chain of Responsibility Pattern?

It lets you build a chain of objects (handlers), where each one can either,
a) Handle the request, and/or
b) Pass it to the next handler in the chain

The sender doesn’t care who ends up handling the request. It just starts the chain.

The Middleware Pipeline

If you have ever worked with ASP.NET Core, Express.js, or similar web frameworks, you would already be familiar with this pattern.

When a request hits your server, it goes through a chain of middleware components which would look something like,
One middleware checks for authentication
Another one logs the request
Another checks if the user is authorized
Yet another serves the final response

Each one does its job (if needed) and then passes the request forward.

That is exactly how the Chain of Responsibility works.

Let’s See It in Code

Let’s imagine you are designing a web request pipeline. You want to handle things like authentication, logging, and actual request processing. But you don’t want all of that cluttered in one place. Instead, you break it down into separate steps, and each step (middleware) focuses on just one responsibility.

You build each middleware like a link in a chain, and then just pass the request along the chain until someone handles it (or the final handler sends a response). It’s a clean, flexible, and intuitive setup.

Here is how it looks in simple pseudocode,

// Step 1: Define a base Handler
Class Middleware
    Property nextMiddleware

    Method SetNext(middleware)
        this.nextMiddleware = middleware
        return middleware

    Method Handle(request)
        CallNext(request)

    Method CallNext(request)
        If nextMiddleware exists:
            nextMiddleware.Handle(request)

// Step 2: Concrete Middlewares
Class AuthMiddleware extends Middleware
    Method Handle(request)
        If request has valid token:
            Print("Authenticated")
            CallNext(request)
        Else:
            Print("Unauthorized request")
            Stop

Class LoggingMiddleware extends Middleware
    Method Handle(request)
        Print("Logging request: " + request.url)
        CallNext(request)

Class FinalHandler extends Middleware
    Method Handle(request)
        Print("Processing request and sending response.")

//caller logic
//Create Handlers
auth = new AuthMiddleware()
logger = new LoggingMiddleware()
handler = new FinalHandler()

//Setup the Chain
auth.SetNext(logger)
logger.SetNext(handler)

//Prepare Incoming Request
request = {
    url: "/api/data",
    token: "a valid token"
}

//Start the Chain
auth.Handle(request)

Enter fullscreen mode Exit fullscreen mode

What Did We Achieve?

  • Handlers are loosely coupled
  • Order of processing is flexible
  • Easy to plug in new middlewares
  • Request is processed step by step, each part is doing its dedicated job

When Should You Use It?

  • When multiple objects can handle a request, and you don’t want the sender to care who handles it
  • When you want to process requests step by step
  • When you want to enable flexible and pluggable flows

Use Cases?

  • Middleware in web frameworks (Express, ASP.NET Core)
  • Event handling systems (GUI toolkits, games)
  • Logging pipelines
  • Tech support systems (Level 1 → Level 2 → Level 3)
  • Access control chains

To summarize it would be apt to say,

Chain of Responsibility Pattern is like a relay baton passed along a chain of handlers. Each gets a chance to process, modify, or reject the request.

Hope this example gave you a clear picture of how the Chain of Responsibility Pattern works, especially in middleware like scenarios, where each handler does one job and passes the request forward. This keeps your code clean, modular, and easy to extend.

Next up in the series: Mediator Pattern. Let’s meet there!

Top comments (0)