わかった気になるRack Middleware
使いたい機能のみを有効にできるmiddleware
という仕組みがrack
にはある。
たとえば、ロギングはmiddleware
で実装するためアプリケーションと疎結合な状態になる。
rackアプリケーションにmiddleware
を追加する方法は、config.ru
などに有効にしたい機能をuse
というキーワードで登録にしていく。
ちなみに、config.ru
はRack::Builder
のインスタンスコンテキストで実行する。
# config.ru
use LoggerMiddleware
run lambda { |env|
[200, {'Content-Type' => 'text/plain'}, ['OK']]
}
middleware
はミルフィーユみたいなもので、リクエストを受け取るとレスポンスを生成するために、middleware
を通過して最終的なレスポンスを評価する。
middleware
として使うクラスにはcall
というメソッドがあれば動作し、
middleware
を使った最小限なrack
アプリケーションは下記な感じで表現できる。
class Middleware
def initialize(app)
@app = app
end
def call(env)
pp 'hello'
@app.call(env)
end
end
app = Rack::Builder.app do
use Middleware
run lambda { |env|
[200, {'Content-Type' => 'text/plain'}, ['OK']]
}
end
server = Rack::Server.new(app: app)
server.start
curl 'http://localhost:8080' # => OK
middleware
の動かし方がわかったのでミルフィーユに深入りしてみる。
use
キーワードによって登録されたmiddleware
クラスがどんな感じでミルフィーユ化するのかを調べたところ、Procでラップしたオブジェクトを配列に追加して、最後にinject
で数珠繋ぎにしている、ということがわかった。
下記は、ミルフィーユ化処理を簡単に書き直したコードである。
class Middle
def initialize(app)
@app = app
end
def call(env)
puts 'hell middleware'
@app.call(env)
end
end
class Builder
def initialize(&block)
@use = []
instance_eval(&block) if block
end
def use(klass, &block)
@use << Proc.new { |app| klass.new(app) }
end
def run
app = ->(x){ '200' }
puts @use.inject(app) { |a, e| e.call(a) }.call('')
end
end
Builder.new {
use Middle
use Middle
}.run
hell middleware
hell middleware
200
以上。
-
category:
- ruby