요청을 처리할 수 있는 처리자들을 사슬로 잇고, 각 처리자가 직접 처리하거나 다음 처리자에게 넘기게 하는 패턴. 요청을 보내는 쪽은 누가 처리할지 몰라도 된다.
type Handler = (req: Req, next: () => Res) => Res
const auth: Handler = (req, next) => (req.user ? next() : { status: 401 })
const rateLimit: Handler = (req, next) => (tooMany(req) ? { status: 429 } : next())
function chain(handlers: Handler[], final: (req: Req) => Res) {
return (req: Req): Res => {
const call = (i: number): Res => (i < handlers.length ? handlers[i](req, () => call(i + 1)) : final(req))
return call(0)
}
}- 웹 프레임워크의 미들웨어(Middleware)가 대표적이다. 인증, 권한, 로깅, 요청 제한을 순서대로 거친다. 스프링 시큐리티의 시큐리티 필터체인, 장고의 Django 미들웨어와 로그인 흐름, Express·NestJS의 미들웨어(NestJS)가 모두 이 구조다
- 처리자를 추가·제거·재배치하기 쉽다
- 순서가 중요하다. 인증보다 권한 검사가 먼저 오면 안 된다
- 아무도 처리하지 않을 수 있으니, 반드시 처리되어야 하는 요청이라면 사슬 끝에 실패 처리를 명확히 둔다
- 흐름이 사슬 전체에 흩어져 있어 어디서 요청이 멈췄는지 추적하기 어렵다. 처리자마다 로그를 남기면 도움이 된다
DOM 이벤트가 요소 트리를 따라 위로 올라가며 처리될 기회를 주는 버블링(Event Bubbling)도 비슷한 모양이다(이벤트 버블링·캡처링과 위임). 요청 제한 처리자의 예는 요청 제한 (Throttling). 행동 패턴 전체는 행동 패턴.