Open10

Faradayとは

いいづかいいづか

Faradayとは?

Faraday is an HTTP client library that provides a common interface over many adapters (such as Net::HTTP) and embraces the concept of Rack middleware when processing the request/response cycle.

  • HTTPクライアントのライブラリ
  • いろんなアダプタに、共通のインターフェースを提供してる
  • リクエスト・レスポンスのサイクルを処理する時にRackミドルウェアの概念を採用してる

https://lostisland.github.io/faraday/

いいづかいいづか

Rachミドルウェアとは?

Rack provides a minimal, modular, and adaptable interface for developing web applications in Ruby. By wrapping HTTP requests and responses in the simplest way possible, it unifies and distills the bridge between web servers, web frameworks, and web application into a single method call.

Rubyにおけるサーバとアプリケーション/フレームワーク間のインターフェースの役割を果たすライブラリ

様々なアプリケーションサーバやフレームワークが開発されても、双方がRackを使用してインターフェース部分を実装していさえすれば、既存のWebアプリケーションをサーバ側の構成を変えることなく新しいフレームワークでリプレイスしたり、あるフレームワークで実装されたアプリケーションを様々な環境に移したり、といったことが容易になります。この「インターフェースが統一されていれば、サーバやフレームワークの組み合わせは自由である」ということが、選択肢の広がった最近のRubyにおけるWeb開発環境にとって重要な意味を持っているのです。

https://github.com/rack/rack
https://gihyo.jp/dev/serial/01/ruby/0023
https://gihyo.jp/dev/serial/01/ruby/0024
https://gihyo.jp/dev/serial/01/ruby/0025

いいづかいいづか

Faraday Middlewareの主な機能

  • authentication
  • caching responses on disk or in memory
  • cookies
  • following redirects
  • JSON encoding/decoding
  • logging
いいづかいいづか

Faraday Middlewareの仕組み

Faraday::Connectionは、HTTPリクエストを作成するRack風ミドルウェアスタックを組み立てるためにFaraday::RackBuilderを使う。それぞれのミドルウェアが実行され、Envオブジェクトを次に渡していく。
最後のミドルウェアが実行された後に、Faraday::Responseをユーザーに返す。

ミドルウェアをスタックする順序は重要である。Rackのように、最初のミドルウェアは他のすべてのミドルウェアをラップし、最後のミドルウェアが最も内側にあるものになる。なので、もしカスタムアダプターを使いたいのなら、1番最後にスタックしなければならない。


参照:https://lostisland.github.io/faraday/middleware/

このおかげで、リトライミドルウェアなるものが実現できる。
ミドルウェアがリクエストとして登録されたかレスポンスとして登録されたかよりも、どのように追加されたかが重要である。

例えば以下のように書くと、

Faraday.new(...) do |conn|
  conn.request :authorization
  conn.response :json
  conn.response :parse_dates
end

ミドルウェアスタックは以下のようになる。

authorization do
  # authorization request hook
  json do
    # json request hook
    parse_dates do
      # parse_dates request hook
      response = adapter.perform(request)
      # parse_dates response hook
    end
    # json response hook
  end
  # authorization response hook
end

この例から、parse_datesがリクエストの1番最後に処理されるミドルウェアであり、レスポンスを処理する最初のミドルウェアであることがわかる。
これが、アダプターが1番最後のミドルウェアに設定されるべき理由である。

いいづかいいづか

Faraday Middlewareの書き方

Middlewareのクラスに#callというインスタンスメソッドを実装する。
これらのミドルウェアが、リクエスト / レスポンスのサイクルにフックする。(処理を割り込ませる)

def call(request_env)
  # do something with the request
  # request_env[:request_headers].merge!(...)

  @app.call(request_env).on_complete do |response_env|
    # do something with the response
    # response_env[:response_headers].merge!(...)
  end
end

レスポンスの処理はon_completeブロックの中で行う。
これにより、リクエストを非同期で処理する並列モードで、ミドルウェアを動作させることができる。

envとは、リクエストとその後のレスポンスの情報を含むシンボルキーを持つハッシュのこと。

例えば、こういうキーがある。

# request phase
:method - :get, :post, ...
:url    - URI for the current request; also contains GET parameters
:body   - POST parameters for :post/:put requests
:request_headers

# response phase
:status - HTTP response status code, such as 200
:body   - the response body
:response_headers

Faraday::Middleware

簡単かつ推奨されているミドルウェアを書く方法は、
Faraday::Middlewareのサブクラスを作成することです。

Faraday::Middlewareには、すでに#callメソッドが実装してあります。また、サブクラスに、#on_request(env)#on_complete(env)2つのメソッドがあるかを探します。

#on_requestはリクエストが作られる際に呼ばれ、リクエストを表すenvが付与されます。
#on_completeは、レスポンスを受け取った後に呼ばれ、レスポンスのenvを受け取ります。

#callメソッドをオーバーライドする必要はあるのか?

ミドルウェアのほとんどが、#callメソッドをオーバーライドする必要はありません。代わりに、on_requeston_completeメソッドを使うことができます。

ただ場合によっては、callをブロック内にラップするなど取り組む必要があります。(例えば、begin-rescueなど)
その場合は、#callメソッドをオーバーライドします。#callメソッドをオーバーライドするときは、ミドルウェアスタックの呼び出しを中断させないよう、必ずapp.call(env)superを呼び出してください。

ミドルウェアのテンプレートはありますか?

以下を参照してください。
https://github.com/lostisland/faraday-middleware-template

https://lostisland.github.io/faraday/middleware/custom