Faraday middlewareの作り方

Faraday middlewareの要件としては、Rack middleware同様に

  • #initialize(app)で他のmiddlewareを引数にとる
  • #call(env)でリクエストの前処理を実装する。

の2点だけを満たせばいい。ただし、レスポンスを処理する場合は#on_complete内のブロックで実装する必要がある。

def call(request_env)
  @app.call(request_env).on_complete do |response_env|
    # パースなどレスポンスの処理
  end
end

ここまではREADME.mdにも書いてあるのだけど、レスポンスの処理を効率的に実装するための方法が用意されている。それはFaraday::Response::Middlewareだ。使い方は以下の通り。

require "faraday"

module Faraday
  class Response
    class JSON < Middleware
      def parse(body)
        body.to_json
      end
    end

    register_middleware json: JSON
  end
end
  • #initialize(app)@app = appのようなことをしているため、特に書く必要はない。特別になにか必要であればoverrideする。
  • #parse(body)でレスポンスをパースの処理を書くと、上述した#on_completeのブロックの中でこのメソッドが呼ばれ、env.body#parse(body)の結果によって更新する。
  • パース以外にレスポンス時の処理を記述したい場合、#on_completeを実装する。このメソッドは上述の#on_completeのブロック内で呼ばれるのだけど、これを実装すると#parseが呼ばれないので注意。
  • Faraday::Response.register_middlewareでキーとミドルウェアを登録できる。このキーを使って以下のように:jsonとミドルウェアを指定できる。
connection = Faraday.new do |connection|
  connection.response :json
  connection.adapter Faraday.default_adapter
end

簡単なのでFaraday::Response::Middlewareのソースコードを見てみる。

module Faraday
  class Response
    class Middleware < Faraday::Middleware
      def call(env)
        @app.call(env).on_complete do |environment|
          on_complete(enrivonment)
        end
      end

      def on_complete(env)
        env.body = parse(env.body) if respond_to?(:parse) && env.parse_body?
      end
    end
  end
end
  • #on_completeブロック内でMiddleware#on_completeが呼ばれていることがわかる。
  • さらにその中で#parseが実装されていれば呼ぶようになっている。
module Faraday
  class Middleware
    extend MiddlwareRegistry

    # ...

    def initialize(app = nil)
      @app = app
    end
  end
end
  • #initializeであとに続くmiddlewareを取り込んでいる。
  • Faraday::MiddlewareRegistryというモジュールで.register_middlewareが定義されており、このメソッドでFaraday middlewareを指定する際のキーを登録できる。