Design Patterns Tutorial 0/70 lessons ~6 min read Lesson 38

    Chain of Responsibility

    Chain of Responsibility arranges handlers in sequence; each handles the request or passes to next.

    Course progress0%
    Focus
    21 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Introduction

    Chain of Responsibility arranges handlers in sequence; each handles the request or passes to next. Shines for preprocessing pipelines: auth → rate limit → validate → route. Express/Koa middleware is Chain of Responsibility made first-class.

    The story

    A B2B API piled auth, rate-limit, schema validation, and observability into every controller. New endpoints kept forgetting one step. Middleware chain at router boundary made controllers 8 lines and impossible to skip essentials.

    The business problem

    Cross-cutting concerns duplicated in every handler cause gaps and drift:

    • Forgotten steps: new endpoint skips auth or rate-limit.
    • Duplicated boilerplate: same 40 lines atop every controller.
    • Reorder pain: changing pipeline order edits every handler.
    • Environment variance: dev skips auth; prod needs it — per-route config hard.

    The problem teams faced

    Chain of Responsibility fits when:

    • Many cross-cutting concerns run per request (auth, validate, log).
    • Concerns must be added/removed/reordered per route or environment.
    • Multiple handlers may process same request (pipeline) or first match wins.
    • Sender should not know which handler ultimately processes request.

    Understanding the topic

    Intent: Avoid coupling sender to receiver; chain handlers until one handles or pipeline completes.

    • Handler — handle(req, next) or setNext chain.
    • ConcreteHandler — processes or forwards.
    • Client — submits to head of chain.
    • Middleware — CoR with next() callback (Express style).

    Internal architecture

    Express middleware chain:

    ts
    app.use(authMiddleware) // 401 or next()
    app.use(rateLimitMiddleware) // 429 or next()
    app.use(validateSchema) // 400 or next()
    app.use(requestLogger)
    app.post("/orders", async (req, res) => {
    const order = await orderService.place(req.body) // 8 lines
    res.json(order)
    })

    Visual explanation

    Three diagrams cover middleware chain, short-circuit, and vs Decorator:

    Middleware pipeline
    Request
    Enters chain
    Auth
    401 or next()
    RateLimit
    429 or next()
    Handler
    Business logic
    Each middleware calls next() or short-circuits response.
    Short-circuit vs pass-through
    Can handle?
    Yes → respond
    Can't handle?
    next()
    Mutate req?
    Enrich context
    Terminal handler
    Last in chain
    Pipeline: all run unless short-circuit. First-match: stop when handled.
    CoR vs Decorator
    Request pipeline?
    CoR middleware
    Wrap same interface?
    Decorator
    next() callback
    CoR signature
    Object wrapper
    Decorator
    CoR chains request processing; Decorator wraps object calls.

    Informative example

    Before / after — duplicated checks to middleware chain:

    ts
    // ❌ Every controller repeats cross-cutting
    app.post("/orders", async (req, res) => {
    if (!req.user) return res.status(401).end()
    if (await rateLimiter.isOver(req.ip)) return res.status(429).end()
    if (!schema.validate(req.body)) return res.status(400).end()
    console.log(req.path)
    // ... actual logic
    })
    // ✅ Chain at router — controller is business only
    const pipeline = [auth, rateLimit, validateOrder, logger]
    app.post("/orders", ...pipeline, placeOrderHandler)
    async function placeOrderHandler(req, res) {
    const order = await orderService.place(req.body)
    res.json(order)
    }

    Execution workflow

    1Middleware chain workflow
    1 / 4

    Identify concerns

    Auth, rate-limit, validate, log, audit.

    List what's duplicated per handler.

    Real-world use

    Express/Koa/ASP.NET middleware, Java Servlet filters, nginx access phases, Kafka interceptor chains, gRPC interceptors, Spring HandlerInterceptor chain.

    Production case study

    B2B API middleware extraction:

    • Scenario: Auth, rate-limit, validation, logging copy-pasted per controller.
    • Decision: Router-level middleware chain; controllers to 8 lines.
    • Outcome: New endpoints can't skip essential steps; order changed in one place.

    Trade-offs

    • Pro: single place per concern; reorder without touching handlers.
    • Pro: compose per route or environment.
    • Con: debugging through long chains — order matters.
    • Con: forgotten next() hangs request silently.

    Decision framework

    • Use when 3+ cross-cutting concerns repeat per request.
    • Use when order of concerns matters and varies.
    • Avoid for single concern — direct middleware function enough.
    • Avoid deep chains without logging — debugging nightmare.

    Best practices

    • One concern per middleware — auth separate from logging.
    • Always call next() or send response — never fall through.
    • Document chain order; test each middleware in isolation.

    Anti-patterns to avoid

    • Mega-middleware doing auth + validate + log + business logic.
    • Business logic in middleware — belongs in handler.
    • 20-layer chain with no tracing.

    Common mistakes

    • Forgotten next() — request hangs until timeout.
    • Error swallowed without passing to error middleware.
    • Async middleware without proper error forwarding.

    Debugging tips

    • Log middleware name at entry/exit with request ID.
    • Temporarily bisect chain — disable half to find failure.

    Optimization strategies

    • Skip expensive middleware when feature flag off early in chain.
    • Cache auth result on req context — don't re-validate in every middleware.

    Common misconceptions

    • CoR ≠ Decorator. CoR processes requests through pipeline; Decorator wraps object interface.
    • Express middleware is CoR — canonical modern example.
    • CoR in event systems — command validation pipeline before aggregate.

    Advanced interview questions

    Interview Prep

    Practice concise answers, then expand each card for the explanation.

    4 questions
    1IntermediateQuestionChain of Responsibility vs Decorator?+

    Answer

    CoR: request through handler chain with next(). Decorator: wrap object, same interface, add behaviour around method calls.

    Follow-up

    Express example?
    2BeginnerQuestionForgotten next() symptom?+

    Answer

    Request hangs — no response until client timeout. Handler never reached.

    Follow-up

    Error middleware?
    3IntermediateQuestionOrder auth vs logger?+

    Answer

    Logger often outermost to capture total time including auth failures. Auth before business handler.

    Follow-up

    Rate limit position?
    4AdvancedQuestionCoR in event-driven systems?+

    Answer

    Command pipeline: validate → authorize → enrich → audit before aggregate handles — same chain pattern.

    Follow-up

    vs Saga?

    Summary

    You can build middleware pipelines, avoid duplicated cross-cutting, and debug chain order. Tell the B2B API controller story — if you can do that, you own Chain of Responsibility.

    Ready to mark this lesson complete?Track your journey across the entire course.