LoginSignup
202
152

More than 5 years have passed since last update.

RubyのHTTPリクエストをできるだけシンプルに実装する

Last updated at Posted at 2018-12-29

背景

Rubyの標準ライブラリであるnet/httpを用いたHTTPリクエストって、Net::HTTP.newしたりNet::HTTP::Get.newしたりhttp.start {...}したり色々と実装が面倒臭いなとずっと思っていたんですが、実は1行で書けることを知ったので open-uri との比較も含めて少しまとめてみました。

環境

  • Ruby 2.6.0

目次

  1. 一番シンプルな方法
  2. リクエストヘッダを指定する方法
  3. Basic認証を使う方法
  4. Proxyを挟む方法
  5. open-uri を使う方法

一番シンプルな方法

GET

require "net/http"

uri = URI.parse("https://jsonplaceholder.typicode.com/todos/1")
response = Net::HTTP.get_response(uri)

response.code # status code
response.body # response body

ポイント

  • Net::HTTP.get_response(uri)の引数はURIクラスのインスタンスのみ。文字列のURLを入れるとNoMethodError: undefined method 'hostname'とかいうエラーが返る。
  • response.code は数字が文字列型で返ってくる("200"みたいな)。
  • response.body は文字列型なので、JSONレスポンスの場合はパースする必要がある。

POST

require "net/http"

params = { title: "my task" }
uri = URI.parse("https://jsonplaceholder.typicode.com/todos")
response = Net::HTTP.post_form(uri, params)

response.code # status code
response.body # response body

ポイント

  • Net::HTTP.post_form 第一引数にURIクラスのインスタンス、第二引数にハッシュ形式でリクエストボディを渡す。
  • Content-Typeapplication/x-www-form-urlencoded 形式になる。
  • params の中に File オブジェクトを入れてみたが、文字列に変換されてしまった。

リクエストヘッダを指定する方法

GET

シンプルな書き方

require "net/http"

uri = URI.parse("https://jsonplaceholder.typicode.com/todos/1")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme === "https"

headers = { "Content-Type" => "application/json" }
response = http.get(uri.path, headers)

response.code # status code
response.body # response body

よく紹介される書き方

require "net/http"

uri = URI.parse("https://jsonplaceholder.typicode.com/todos/1")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme === "https"

headers = { "Content-Type" => "application/json" }
req = Net::HTTP::Get.new(uri.path)
req.initialize_http_header(headers)

response = http.request(req)

response.code # status code
response.body # response body

ポイント

  • Net::HTTP.newの第一引数にホスト名、第二引数にポートを渡す。
  • httpsで始まるURLにアクセスする場合はNet::HTTP#use_ssl=trueを渡す。
  • Net::HTTP#get の第一引数にパス名、第二引数にリクエストヘッダを渡す。
  • Net::HTTP::Get を使う場合は、初期化時の第一引数にはパス名を渡し、Net::HTTP::Get#initialize_http_header にハッシュを渡せばリクエストヘッダを指定できる。
  • Net::HTTP::Get#[]= でもヘッダを指定できる。
    • req["Content-Type"] = "application/json" みたいな。

POST

シンプルな書き方

require "net/http"
require "json"

uri = URI.parse("https://jsonplaceholder.typicode.com/todos")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme === "https"

params = { name: "Takuya" }
headers = { "Content-Type" => "application/json" }
response = http.post(uri.path, params.to_json, headers)

response.code # status code
response.body # response body

よく紹介される書き方

require "net/http"

uri = URI.parse("https://jsonplaceholder.typicode.com/todos")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme === "https"

params = { name: "Nobuto" }
headers = { "Content-Type" => "application/json" }

req = Net::HTTP::Post.new(uri.path)
req.set_form_data(params)
req.initialize_http_header(headers)

response = http.request(req)

response.code # status code
response.body # response body

ポイント

  • Net::HTTP#postの第一引数にパス名、第二引数にリクエストボディ、第三引数にリクエストヘッダを渡す。
  • Net::HTTP#postを使う場合、リクエストボディは文字列を渡す。
  • Net::HTTP::Post#set_form_dataを使う場合、リクエストボディはハッシュを渡す。
  • Content-Typeを指定しなければ自動でapplication/x-www-form-urlencodedが指定される。

Basic認証を利用する方法

URIオブジェクトを使う方法

require "net/http"

uri = URI.parse("https://username:password@jsonplaceholder.typicode.com/todos/1")
response = Net::HTTP.get_response(uri)

response.code # status code
response.body # response body

ポイント

  • URI.parseに渡すURLをプロトコル://ユーザー名:パスワード@ホスト名・パス名形式で書けばOKなので、多分これが一番シンプル。

Net::HTTP::Get#basic_authを使う方法

require "net/http"
username, password = "username", "password"
uri = URI.parse("https://jsonplaceholder.typicode.com/todos/1")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = uri.scheme === "https"

req = Net::HTTP::Get.new(uri.path)
req.basic_auth(username, password)
response = http.request(req)

response.code # status code
response.body # response body

Proxyを挟む方法

require "net/http"

base_uri = URI.parse("https://jsonplaceholder.typicode.com/todos/1")
proxy_uri = URI.parse("http://username:password@proxy-server.com")

http = Net::HTTP.new(base_uri.host, base_uri.port, proxy_uri.host, proxy_uri.port, proxy_uri.username, proxy_uri.password)
http.use_ssl = base_uri.scheme === "https"
response = http.get(base_uri.path)

response.code # status code
response.body # response body

ポイント

  • Net::HTTP.newの第三引数以降にプロキシサーバーのホスト名、ポート、ユーザー名、パスワードを渡せば、他は通常のHTTPリクエストと同様に書ける。

Net::HTTPResponseについて

余談ではあるが、レスポンスとして返ってくるNet::HTTPResponseオブジェクトのメソッドについて見てみたい。

Net::HTTPResponse#body -> String

  • 文字列型でレスポンスボディを返す。

Net::HTTPResponse#code -> String

  • 文字列型でステータスコードを返す。

Net::HTTPResponse#http_version -> String

  • 文字列型でHTTPのバージョンを返す。

Net::HTTPResponse#message -> String

  • 文字列型でステータスコードのメッセージを返す。

Net::HTTPResponse#value -> nil

  • レスポンスコードが2xxの場合はnilを返す。
  • レスポンスコードが3xxの場合は例外HTTPRetriableErrorraiseする
  • レスポンスコードが4xxの場合は例外HTTPServerExceptionraiseする
  • レスポンスコードが5xxの場合は例外HTTPFatalErrorraiseする
  • レスポンスコードが1xxもしくは未知のコードの場合は例外HTTPErrorraiseする
require "net/http"

uri = URI.parse("https://jsonplaceholder.typicode.com/todos/1")
response = Net::HTTP.get_response(uri)

p response.code # -> "200"
p response.body # -> "{ \"userId\": 1, \"id\": 1, \"title\": \"delectus aut autem\", \"completed\": false}"
p response.http_version # -> "1.1"
p response.message # -> "OK"
p response.value # -> nil

なんで#valueってプロパティのようなメソッド名なのに例外をraiseするっていう処理内容なのかちょっと謎。

open-uri を使う方法

Kernel.#openを使う方法

require "open-uri"

open("https://jsonplaceholder.typicode.com/todos/1").read # response body

URI#openを使う方法

require "open-uri"

uri = URI.parse("https://jsonplaceholder.typicode.com/todos/1")
uri.open.read # response body

リクエストヘッダを指定する方法

require "open-uri"

open("https://jsonplaceholder.typicode.com/todos/1",
  "User-Agent" => "Ruby/#{RUBY_VERSION}"
).read # response body

ポイント

  • open-uriはGETリクエストのみ対応。
  • open-urirequireするとURIURI#openメソッドが追加される。
  • openメソッドの第二引数以降にキーワード引数形式でリクエストヘッダを指定できる。
  • ステータスコードが2xxでなかった場合にはOpenURI::HTTPErrorraiseする。

感想

  • 何の変哲も無いGET/POSTリクエストについてはNet::HTTP.get_responseNet::HTTP.post_formがシンプルなので積極的に使っていきたい。
  • ちょっとカスタマイズする必要がある場合はNet::HTTP#getNet::HTTP#postを使う。ほとんどの場合Net::HTTP::GetNet::HTTP::Postを使う必要なさそう。
  • Rails環境ではnet/httprequireなしで実行できる一方でopen-urirequireが必要なので、特に理由が無ければ前者を使っていきたい。

参考

202
152
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
202
152