HTTPフレームワークのミドルウェア再考
モダンなHTTPフレームワークに必ずと行っていいほどある仕組み、それがミドルウェアである
code:js
server.get("/", req => {
// ... 処理
})
このようなルート定義とリクエストを引数に持ったハンドラというスタイルのサーバーはsinatra以降に特に支持されており、Node.jsのExpress、Goのhttpなどで見ることができる。
こういった仕組みはとてもシンプルで便利なのだが、実際のアプリケーションを開発する上では機能不足になる
というのも、ルートとハンドラが1対1対応しているということはつまり、どのルートも必ずすべての処理をそのハンドラの中で完結させなければいけないということを意味する
つまりどのルートでも必ず行いたい処理などを重複して書かざるを得ないということだ
その代表とも言える処理が認証である
ログインができるサイトであれば、特定のルートはログインしていなければ見れてはいけない
そうなるとこういう処理が必要になってくる
code:js
server.get("/mypage", req => {
if(isAuthenticated(req)){
// ログイン済み
const user = getUser(req);
} else {
// ログインしてない
req.respond({status: 401})
}
})
このページだけならばいいが、同様のページがたくさんあるとだんだん面倒になってくるしコードも煩雑になる
そもそもログインされてなければ404や401を返さないといけないことが確定しているのであれば、後半の処理も認証の処理もこの中でやる必要はないはずである。認証済みのリクエストだけがこのハンドラに到達し欲しいわけなので
そういう複数のハンドラに到達する前にリクエストをプロセスしてフィルタするための仕組みをHTTPミドルウェアと呼ぶ
ExpressのミドルウェアはJavaScriptの柔軟な言語仕様を使った画期的な仕組みで、
code:js
function authenticate(req, res, next) {
if (isAuthenticated(req) {
// ユーザ情報を取得して追加する
req.user = getUser(req);
// 次のミドルウェアを呼ぶ
next();
} else {
// この時点でレスポンスを返し以降のミドルウェアを実行しない
res.status(401);
}
}
server.get("/mypage", authenticate, req => {
// 認証済みで、ユーザ情報が格納されたリクエストだけ来る
const user = req.user;
})
このように共通のリクエスト処理を関数として定義し、フィルターやマッパーとして追加できるようなっている
この仕組みはExpressがかつて使っていたConnectというミドルウェアシステム由来のものなのだが…
この仕組みの良いところは、ピュアなJavaScriptの仕組みだけですべてのロジックが実装されており、度を超えた抽象化がされていないという点にある
ミドルウェアをチェーンしていく仕組みはmapやfilterあるいはreduceに似ていて、関数チックな思想を理解していればすぐに仕組みがわかる
一方で、RailsやSpring-Boot、FlaskなどのDRY系のフレームワークはこういった明示的な処理をアノテーションで記述しようとする
アノテーションはフレームワークの中で最も使ってはいけない機能だと僕は思っている
なぜかといえば、アノテーションがよく魔法(あるいは黒魔術)と呼ばれるように、プログラムの仕組みを逸脱してしまっているからである。クラスのメソッドに@GET, @Path("/")というアノテーションをつけたら"/"へ来たGETリクエストがそのメソッドに来る、ということは説明はできるし実際にそう動くわけだけど、それはもう通常のプログラムでは無い
なぜかと言えばそういったアノテーションはあくまでコードのメタデータであり、そのメタデータがどういうふうな副作用を生むのかというのは常に不定だからだ
そして特殊なフレームワークを使わない限り、アノテーションは通常のプログラムでは使われないというところに大きな問題がある
ライブラリやフレームワークはコード資産を再利用するという目的のためにあるわけだが、コードが有るならその提供方法もコードであるべきである。なぜ明示的なプログラムでないそういった要素を使わせようとするのかが理解できない。
そういった仕組みは常に「初心者向け」や「簡単」と言った言葉でのらりくらりとしているが、実際その結果が汎用的なプログラムでない単なるDLSである以上、ユーザーはいつまで経ってもサーバーの仕組みを理解できない
まぁ確かにWebサイトを作ることに興味がある人にとってHTTPの仕組みはどうでもいいかもしれない
しかしブログやSNSがある現代において自分でWebサイトをプログラムしようとする人は、HTTPの仕組みは知っておくべきである
HTTPはとても簡単なプロトコルである
光ファイバーから数えて7層もの通信の抽象化の上に成立していて、ちょっとした文字列を返すだけでブラウザがそれを書籍やらアプリやら動画やら音楽やらにしてくれる素晴らしく現代における最も便利な仕組みのひとつである