Ruby HTTPクライアントの比較表

Rubyには標準でnet/httpが入っていますが、これはちょっと低レイヤ寄りで使いづらいので、使いやすくしたHTTPクライアントライブラリが多数あります。

ありすぎてどれを選んでいいか調べていたところ、HTTPClientの作者さんによる比較スライドを見つけました：
http://www.slideshare.net/HiroshiNakamura/rubyhttp-clients-comparison

まとめると

- httpartyとrest-clientが2大人気（ソースはGemのダウンロード数とgithubのスター数。faradayはラッパーなので別枠）
- この2つで出来ることはほとんど同じ
- 違いはDigest認証（httppartyは可）、multipart post（rest-clientは可）くらい
- どちらもKeep-Aliveに対応していない
- HTTPClientはDigest認証も対応しているし、Keep-Aliveも自動的に面倒見てくれるし、機能的にはフルカバーっぽい

こちらの記事でも「HTTPClientは宣伝がうまくないだけでベストなgemだ」みたいな事が書かれている。
https://bibwild.wordpress.com/2012/04/30/httpclient-is-a-nice-http-client-forin-ruby/

…しかし、もしかしたらすでにfaradayがデファクトスタンダードになりつつあるのかもしれない。
faradayの短所はドキュメントがしっかりしてないことだな。

## HTTPClientの使い方

```rb
require 'httpclient'

client = HTTPClient.new
client.debug_dev = $stderr    # デバッグ情報を標準エラー出力に

query = {'q' => 'google 倒産', 'hl' => 'ja'}
# get
res = client.get('https://google.co.jp', :query => query, :follow_redirect => true)
# post
#res = client.post('http://httpbin.org/post', :body => query)

puts "code=#{res.code}"    # res.code : Fixnum
puts HTTP::Status.successful?(res.code)
p res.headers
puts res.body
```

github：https://github.com/nahi/httpclient
ドキュメント：http://www.rubydoc.info/gems/httpclient/HTTPClient

### プロキシの使用

HTTPClientは（net/httpと同じく）環境変数`http_proxy`を参照する。
明示的にプロキシを指定したい場合は:

```rb
proxy = 'http://**********:8080'
client = HTTPClient.new(proxy)

# さらにプロキシにBASIC認証したい場合は:
#user = 'proxy'
#password = 'proxy'
#client.set_proxy_auth(user, password)
#p client.get(url)
```

環境変数`http_proxy`を無視してプロキシを使用しないようにするには:

```
client = HTTPClient.new
client.proxy = nil
```

### リクエストヘッダの指定

```
res = client.get('https://google.co.jp', query: query, header: [["User-Agent", "hoge"]], follow_redirect: true)
```

## Faradayの使い方

### 一番シンプルな方法

```rb
require "faraday"
res = Faraday.get "http://httpbin.org/get", {a: "hoge"}
res = Faraday.post "http://httpbin.org/post", {a: "hoge"}
p res.status    # => 200
p res.success?  # => true
res.headers.each do |k, v|
  puts "#{k}: #{v}"
end
puts res.body
```

### もう少し凝った方法

```rb
conn = Faraday.new(:url => 'http://sushi.com') do |faraday|
  faraday.request  :url_encoded             # form-encode POST params
  faraday.response :logger                  # log requests to STDOUT
  faraday.adapter  Faraday.default_adapter  # make requests with Net::HTTP
end

## GET ##

response = conn.get '/nigiri/sake.json'     # GET http://sushi.com/nigiri/sake.json
response.body

conn.get '/nigiri', { :name => 'Maguro' }   # GET http://sushi.com/nigiri?name=Maguro

conn.get do |req|                           # GET http://sushi.com/search?page=2&limit=100
  req.url '/search', :page => 2
  req.params['limit'] = 100
end

## POST ##

conn.post '/nigiri', { :name => 'Maguro' }  # POST "name=maguro" to http://sushi.com/nigiri

# post payload as JSON instead of "www-form-urlencoded" encoding:
conn.post do |req|
  req.url '/nigiri'
  req.headers['Content-Type'] = 'application/json'
  req.body = '{ "name": "Unagi" }'
end

## Per-request options ##

conn.get do |req|
  req.url '/search'
  req.options.timeout = 5           # open/read timeout in seconds
  req.options.open_timeout = 2      # connection open timeout in seconds
end
```

### ホスト部とパス部を分けずに書くこともできるらしい

```rb
faraday = Faraday.new
res = faraday.post "http://httpbin.org/post", {q: "hgoehoge", a: 123}
```

### 1行でJSONをPOSTする

```rb
res = Faraday.post "https://httpbin.org/post", JSON.generate({hoge: 123, moge: [1,2,3]}), content_type: "application/json"
```

### 標準出力でなく指定ファイルにログを吐く方法

```rb
require "logger"

my_logger = Logger.new("logfile.log")
my_logger.level = Logger::DEBUG

conn = Faraday.new(:url => "https://httpbin.org") do |faraday|
  faraday.request  :url_encoded
  faraday.response :logger, my_logger # <-- sets a custom logger.
  faraday.adapter  Faraday.default_adapter
end


conn.get "/get", {hoge: 123}

```


## net/httpの使い方

```
require "net/http"
require "uri"
```

### シンプルなGET

```ruby
url = "https://ipinfo.io"
puts Net::HTTP.get(URI.parse(url))
# => String（レスポンスボディ）
```

### シンプルなPOST（x-www-form-urlencoded）

```ruby
url = "https://httpbin.org/post"
params = {a: 123, b: "hoge"}
ret = Net::HTTP.post_form(URI.parse(url), params)
puts ret.code
puts ret.body
```

### シンプルなPOST（JSON）

```ruby
url = "https://httpbin.org/post"
payload =  {
  a: 123, b:"hoge"
}

uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
req = Net::HTTP::Post.new(uri.request_uri)
req["Content-Type"] = "application/json"
req.body = payload.to_json
res = http.request(req)

puts "code -> #{res.code}"
res.each_capitalized_name do |name|
  value = res[name]
  puts "#{name} = #{value}"
end
puts "body -> #{res.body}"
```

## つぶやき

HTTPクライアントの使い方を調べるときは以下のやり方を抑えておこうと思った。

- シンプルなGET
- シンプルなPOST（x-www-form-urlencoded）
- JSONのPOST
- リクエストヘッダの指定
- リダイレクトをたどるか
- プロキシの指定
- BASIC認証
- ファイルのアップロード
- レスポンスのステータスコードはIntegerかStringか