middlewareパターンとは、handle関数を受けてhandle関数を返す高階関数
middlewareパターンとは、handle関数を受けてhandle関数を返す高階関数
code:ts
type Handler = (req:Request) => Response
type Middleware = (next:Handler) => Handler
型定義だけだと、高階関数であるせいか理解が難しい
図で考えると分かりやすいですmiyamonz.icon
https://gyazo.com/74c29b6d4fa9db1ad5a91cb19ffdedc4
(この図は適当にネットから拾ったものです)
真ん中のauth middlware基準で考えると、authに対して右側全体が後続処理である。なので、
https://gyazo.com/2b275799145a3e4549c75f3ef00a85b7
authを基準として、nextというのは右の領域を意味する。
nextはrequest -> responseという形になっている
さて、auth middlewareを結合すると
https://gyazo.com/10a1b9e0117186df7601ffbd9f9f5e5f
この様になるのだか、これ自身もまた、request -> responseの形を維持している
境界が一層左にずれただけ
これが次のlog middlewareからみたnextに相当する
だから、middlewareという構造、あるいは型定義は、
request -> responseを受けて、
request -> responseを返す関数の構造をしているのである。
https://gyazo.com/ff4c4c43592f152b93d70bf80e1cd834
request -> response という関数は、図でいうと層の境界面に相当する
なので、middlewareが「境界面を引数として受取り、新しい境界面を返す」と考えると、
type Middleware = (next: Handler) => Handler;はとても自然に見えるはずだ
そうすると、複数のmiddlewareを結合するcombine関数が、reduceRightである理由も分かるだろう
code:ts
function combine(...middlewares: Middleware[]): Middleware {
return initial =>
middlewares.reduceRight(
(next, middleware) => middleware(next),
initial,
);
}
図のようなlog, auth, cache ミドルウェアを並べたとき、
まず右端のcacheからはじめないといけない
combineとは、nextをwrapして新しいmiddlewareを作るから、右端終端からはじめないといけないということだ
だからreduceRightなのである
また、一番右端の部分(例のコードだとinitialReducer)を引数に取るように書いてるので、combine自身もまた、Middleware型になるのである
これは、層を複数重ねたものも、一つの層をなすということと同じである