ykominami
5/23/2012 - 1:48 PM

Ruby の HTTP クライアントライブラリ Faraday が便利そう

Ruby の HTTP クライアントライブラリ Faraday が便利そう

Ruby の HTTP クライアントライブラリ Faraday が便利そう

Ruby の HTTP クライアントライブラリ Faraday が便利そう

API ラッパの開発には RestClient gem だとか
OAuth の必要なものは Net/HTTP + OAuth gem を使ってた

Twitter gemInstagram gem など API ライブラリのソースを読んでみると
Faraday gem というものがよく使われてた

なんとなく気になったので Faraday について調べてみた
ついでに Tumblife gem を Faraday を使うようにした

以下そのメモ


Faraday って何?

Faraday is an HTTP client lib 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.

Faraday は HTTP クライアントライブラリ
Net::HTTP やその他の多くのアダプタに共通のインターフェースを提供し
また Rack ミドルウェアのようなインターフェースでリクエスト/レスポンスのサイクルを処理することが出来る


Faraday でサポートしてるアダプターは?

  • Net/HTTP
  • Excon
  • Typhoeus
  • Patron
  • EventMachine

使い方は?

こんな感じで使える
builder.use で使用するミドルウェアを宣言する

conn = Faraday::Connection.new(:url => 'http://example.com') do |builder|
  builder.use Faraday::Request::UrlEncoded  # リクエストパラメータを URL エンコードする
  builder.use Faraday::Response::Logger     # リクエストを標準出力に出力する
  builder.use Faraday::Adapter::NetHttp     # Net/HTTP をアダプターに使う
end

response = conn.get '/api/nyan.json' # GET http://example.com/api/nyan.json
puts response.body

あるいは Faraday::Connection.new ... の部分はこうとも書ける

conn = Faraday.new(:url => 'http://example.com') do |builder|
  builder.request  :url_encoded
  builder.response :logger
  builder.adapter  :net_http
end

また GET リクエストの送信部分もこう書くことも出来る

conn.get '/api/nyan.json', {:color => :black} # GET http://example.com/api/nyan.json?color=black

response = conn.get do |req|  # GET http://example.com/api/nyan.json?color=white&size=big
  req.url '/api/nyan.json', {:color => :white}
  req.params[:size] = :big
end

POST はこう書く

conn.post '/api/wan.json', {:color => :black} # POST "color=black" to http://example.com/api/nyan.json

conn.post do |req|
  req.url '/api/wan.json'
  req.body = {
    :color => :black,
    :size  => :big
  }
end

ファイルのアップロードも出来る

conn = Faraday.new(:url => 'http://example.com') do |builder|
  builder.request :multipart   # マルチパートでデータを送信
  builder.request :url_encoded
  builder.adapter :net_http
end

params = {
  :name    => 'nyanco',
  :picture => Faraday::UploadIO.new('nyanco.jpg', 'image/jpeg')
}
conn.put '/api/nyan.json', params

ミドルウェアを使う

上記の他にこんなミドルウェアがある
主要(と思われる)ものだけ抜粋した

  • request

    • :basic_authentication (ベーシック認証)
    • :retry (リクエスト失敗時に指定回数まで再接続する)
  • response

    • :raise_error (4xx, 5xx エラー時に例外を投げる)

他に FaradayMiddleware gem というナイスなライブラリがあって
これを使うと色々な便利ミドルウェアが使えるようになる

  • request

    • :oauth (OAuth 対応 / SimpleAuth gem 依存)
    • :oauth2 (OAuth2 対応)
  • response

    • :caching (レスポンスをキャッシュする)
    • :parse_json (レスポンスの JSON を Hash 形式で返す / JSON gem 依存)
    • :parse_xml (レスポンスの XML を Hash 形式で返す / MultiXML gem 依存)
    • :mashify (レスポンスの Hash を Hashie::Mash 形式で返す / Hashie gem 依存)
    • :follow_redirects (リダイレクトを追う)

便利そうなのはこんなところか

因みにミドルウェアへパラメータを渡す時は、ミドルウェアの宣言時の第二引数以降で渡す
ミドルウェアは宣言した順番と逆に呼び出されるので書く順番には注意

conn = Faraday.new(options) do |builder|
  credentials = {
    :consumer_key    => consumer_key,
    :consumer_secret => consumer_secret,
    :token           => oauth_token,
    :token_secret    => oauth_token_secret
  }
  builder.request :oauth, credentials
end

その他詳しいオプションとか使い方は各公式ドキュメント見てくれ


ミドルウェアを自分で拡張する

call メソッドが実装されたクラスを作る
Faraday::Middleware を継承すると面倒見てくれるので便利

class MyMiddlewre < Faraday::Middleware
  def call(env)
    # リクエストに対して何かしたい場合はここに書く

    @app.call(env).on_complete do
      # レスポンスに対して何かしたい場合はここに書く
    end
  end
end

env には以下のものが Hash で入ってる

  • request phase

    • :method
    • :url
    • :body
  • response phase

    • :status
    • :body
    • :response_headers

レスポンスだけ弄りたい場合は Faraday::Response::Middleware を継承すれば良い

class MyResponseMiddleware < Faraday::Response::Middleware
  def on_complete(env)
    # レスポンスに対して何かする
  end
end

因みに Tumblife gem では下記のミドルウェアを自分で拡張したので参考までに


結局 Faraday を使うと何が嬉しいの?

  • HTTP リクエスト部分が宣言的に美しく書ける
  • リクエスト/レスポンスが柔軟に設定出来る

自分で使ってて感じたのはこのくらいか
有名な API ライブラリが使ってるから...という感じは否めない
でも慣れてきたら便利な気がする

あと OAuth / OAuth2 両方に対応してるので
API によって gem を使い分けるみたいな面倒くさいことしなくても良い


その他

使用できるアダプターにある EventMachine がちょっと気になってる
これを使うと並列かつ非同期でリクエストが送れたりするのだろうか
クローラ等作るのに便利そうなので気が向いたら調べてみよう


参考

Faraday gem wiki
Faraday Middleware gem wiki