いつもhttpリクエストでどういう実装するのか悩むのでコピペですぐ使えるようにする。
faradayを経験してみる
/System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/net/protocol.rb:44:in `connect_nonblock': SSL_connect returned=1 errno=0 state=SSLv3 read server hello A: sslv3 alert handshake failure (OpenSSL::SSL::SSLError)
- https://jsonplaceholder.typicode.com/
- https://jsonplaceholder.typicode.com/todos/1
- https://h5y1m141.github.io/step-up-javascript/doc/use_jsonplaceholder_with_chrome.html
- https://qiita.com/takano-h/items/dd10818eb7e09161bc29 これを経験してみる
ruby version
$ ruby -v
ruby 2.6.3p62 (2019-04-16 revision 67580) [universal.x86_64-darwin19]
rubyのマニュアルはどこにあるの?
ruby マニュアルで検索
https://docs.ruby-lang.org/ja/
https://docs.ruby-lang.org/ja/2.6.0/doc/index.html
httpはネットワークのところにあった。
https://docs.ruby-lang.org/ja/2.6.0/library/index.html
https://docs.ruby-lang.org/ja/2.6.0/library/net=2fhttp.html
マニュアルに沿って試してみる
例1: GET して 表示するだけ。httpでアクセスしていると思う
$ cat test.rb
require 'net/http'
Net::HTTP.get_print 'jsonplaceholder.typicode.com', '/todos/1'
$ ruby test.rb
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
-
Net::HTTP.get_printの機能を調べるにはどうするか?
- https://docs.ruby-lang.org/ja/latest/class/Net=3a=3aHTTP.html
- 非常にわかりづらい,ページした方の方に各メソッドのリンクがある
-
URI.parseのマニュアルは?
例2: URI を使う
$ cat test.rb
require 'net/http'
require 'uri'
Net::HTTP.get_print URI.parse('http://jsonplaceholder.typicode.com/todos/1') # httpsにすると動かなかった
$ ruby test.rb
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
例3: より汎用的な例
require 'net/http'
require 'uri'
url = URI.parse('http://jsonplaceholder.typicode.com')
res = Net::HTTP.start(url.host, url.port) {|http|
http.get('/todos/1')
}
puts res.body
$ ruby test.rb
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}
- http.start https://docs.ruby-lang.org/ja/latest/method/Net=3a=3aHTTP/s/start.html
- http.get https://docs.ruby-lang.org/ja/latest/method/Net=3a=3aHTTP/s/get.html
例4: 上の例よりさらに汎用的な例
require 'net/http'
url = URI.parse('http://www.example.com/index.html')
req = Net::HTTP::Get.new(url.path)
res = Net::HTTP.start(url.host, url.port) {|http|
http.request(req)
}
puts res.body
結果は省略、動いた
- Net::HTTP::Get.new https://docs.ruby-lang.org/ja/latest/class/Net=3a=3aHTTP=3a=3aGet.html
リクエストヘッダを指定する方法、portも変える
https://qiita.com/takano-h/items/dd10818eb7e09161bc29
https://qiita.com/mogulla3/items/a4bff2e569dfa7da1896
require "net/http"
uri = URI.parse("http://jsonplaceholder.typicode.com/todos/1")
http = Net::HTTP.new(uri.host, uri.port) # port指定したければuri.portをport番号に置き換える
# puts uri.port # httpなら80、httpsなら443がデフォルト値になる
http.use_ssl = uri.scheme === "https" # uri.schemeがhttp or httpsだと思われ。一致したらtrueをhttp.use_sslを代入する。一致しなければfalseを代入。trueだとsslを使用するという設定になる
headers = { "Content-Type" => "application/json" } # ヘッダーの設定
req = Net::HTTP::Get.new(uri.path)
req.initialize_http_header(headers)
response = http.request(req) # リクエストを投げる
puts response.code # status code
puts response.body # response body
最終形、リクエストを投げて、JSONオブジェクトをHashへパースする
require 'net/http'
require 'uri'
require 'json'
require 'logger'
# [ロガー]
# カレントディレクトリのwebapi.logというファイルに出力
# (DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN)
logger = Logger.new('./webapi.log')
logger.info("start")
# [クエリパラメータ]
# URI.encode_www_formを使って「application/x-www-form-urlencoded」形式の文字列に変換
# 文字列はURLエンコードされた形式に変換(半角スペースの"+"への変換等)
#
# (変換例)
# 'bar baz' => 'bar+baz'
# 'あ' => '%E3%81%82'
# params = URI.encode_www_form({ param1: 'foo', param2: 'bar baz' , param3: 'あ' })
# [URI]
# URI.parseは与えられたURIからURI::Genericのサブクラスのインスタンスを返す
# -> 今回はHTTPプロトコルなのでURI::HTTPクラスのインスタンスが返される
#
# オブジェクトからは以下のようにして構成要素を取得できる
# uri.scheme => 'http'
# uri.host => 'mogulla3.com'
# uri.port => 4567
# uri.path => ''
# uri.query => 'param1=foo¶m2=bar+baz¶m3=%E3%81%82'
# uri = URI.parse("http://mogulla3.com:4567?#{params}")
uri = URI.parse("http://jsonplaceholder.typicode.com/todos/1")
begin
# [GETリクエスト]
# Net::HTTP.startでHTTPセッションを開始する
# 既にセッションが開始している場合はIOErrorが発生
response = Net::HTTP.start(uri.host, uri.port) do |http|
# Net::HTTP.open_timeout=で接続時に待つ最大秒数の設定をする
# タイムアウト時はTimeoutError例外が発生
http.open_timeout = 5
# Net::HTTP.read_timeout=で読み込み1回でブロックして良い最大秒数の設定をする
# デフォルトは60秒
# タイムアウト時はTimeoutError例外が発生
http.read_timeout = 10
# Net::HTTP#getでレスポンスの取得
# 返り値はNet::HTTPResponseのインスタンス
http.get(uri.request_uri)
end
# [レスポンス処理]
# 2xx系以外は失敗として終了することにする
# ※ リダイレクト対応できると良いな..
#
# ステータスコードに応じてレスポンスのクラスが異なる
# 1xx系 => Net::HTTPInformation
# 2xx系 => Net::HTTPSuccess
# 3xx系 => Net::HTTPRedirection
# 4xx系 => Net::HTTPClientError
# 5xx系 => Net::HTTPServerError
case response
# 2xx系
when Net::HTTPSuccess
# [JSONパース処理]
# JSONオブジェクトをHashへパースする
# JSON::ParserErrorが発生する可能性がある
# {"userId"=>1, "id"=>1, "title"=>"delectus aut autem", "completed"=>false}
# p JSON.parse(response.body)
result = JSON.parse(response.body)
p result
p result["userId"]
# 3xx系
when Net::HTTPRedirection
# リダイレクト先のレスポンスを取得する際は
# response['Location']でリダイレクト先のURLを取得してリトライする必要がある
logger.warn("Redirection: code=#{response.code} message=#{response.message}")
else
logger.error("HTTP ERROR: code=#{response.code} message=#{response.message}")
end
# [エラーハンドリング]
# 各種処理で発生しうるエラーのハンドリング処理
# 各エラーごとにハンドリング処理が書けるようにrescue節は小さい単位で書く
# (ここでは全て同じ処理しか書いていない)
rescue IOError => e
logger.error(e.message)
rescue TimeoutError => e
logger.error(e.message)
rescue JSON::ParserError => e
logger.error(e.message)
rescue => e
logger.error(e.message)
ensure
logger.info("end")
end
----------------
$ ruby test.rb
{"userId"=>1, "id"=>1, "title"=>"delectus aut autem", "completed"=>false}
1
- 返り値はNet::HTTPResponseのインスタンス https://docs.ruby-lang.org/ja/latest/class/Net=3a=3aHTTPResponse.html
- logger https://docs.ruby-lang.org/ja/latest/class/Logger.html
- https://jsonplaceholder.typicode.com/todos/1 応答がないことがよくある
httpsでGETする。postが必要になったらまた調査しよう
require 'net/https'
require 'uri'
require 'json'
require 'logger'
# [ロガー]
# カレントディレクトリのwebapi.logというファイルに出力
# (DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN)
logger = Logger.new('./webapi.log')
logger.info("start")
# [クエリパラメータ]
# URI.encode_www_formを使って「application/x-www-form-urlencoded」形式の文字列に変換
# 文字列はURLエンコードされた形式に変換(半角スペースの"+"への変換等)
#
# (変換例)
# 'bar baz' => 'bar+baz'
# 'あ' => '%E3%81%82'
# params = URI.encode_www_form({ param1: 'foo', param2: 'bar baz' , param3: 'あ' })
# [URI]
# URI.parseは与えられたURIからURI::Genericのサブクラスのインスタンスを返す
# -> 今回はHTTPプロトコルなのでURI::HTTPクラスのインスタンスが返される
#
# オブジェクトからは以下のようにして構成要素を取得できる
# uri.scheme => 'http'
# uri.host => 'mogulla3.com'
# uri.port => 4567
# uri.path => ''AA
# uri.query => 'param1=foo¶m2=bar+baz¶m3=%E3%81%82'
uri = URI.parse("https://jsonplaceholder.typicode.com/todos/1")
begin
# [GETリクエスト]
# Net::HTTP.startでHTTPセッションを開始する
# 既にセッションが開始している場合はIOErrorが発生
# httpのようにブロックを使ったら動かなかった
# HTTP.startは使えない。startを使うと、すぐにsessionを貼るので、https.use_ssl=falseができない
https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = uri.scheme === "https"
https.verify_mode = OpenSSL::SSL::VERIFY_NONE # テストのときはこれでよい。社内テストでエラーのときは対応が必要。ssl証明書を取得してあげる?
# Net::HTTP.open_timeout=で接続時に待つ最大秒数の設定をする
# タイムアウト時はTimeoutError例外が発生
https.open_timeout = 5
# Net::HTTP.read_timeout=で読み込み1回でブロックして良い最大秒数の設定をする
# デフォルトは60秒
# タイムアウト時はTimeoutError例外が発生
https.read_timeout = 10
req = Net::HTTP::Get.new(uri.request_uri)
response = https.request(req)
# [レスポンス処理]
# 2xx系以外は失敗として終了することにする
# ※ リダイレクト対応できると良いな..
#
# ステータスコードに応じてレスポンスのクラスが異なる
# 1xx系 => Net::HTTPInformation
# 2xx系 => Net::HTTPSuccess
# 3xx系 => Net::HTTPRedirection
# 4xx系 => Net::HTTPClientError
# 5xx系 => Net::HTTPServerError
case response
# 2xx系
when Net::HTTPSuccess
# [JSONパース処理]
# JSONオブジェクトをHashへパースする
# JSON::ParserErrorが発生する可能性がある
# {"userId"=>1, "id"=>1, "title"=>"delectus aut autem", "completed"=>false}
# p JSON.parse(response.body)
result = JSON.parse(response.body)
p result
p resul["userId"]
# 3xx系
when Net::HTTPRedirection
puts "baaa"
# リダイレクト先のレスポンスを取得する際は
# response['Location']でリダイレクト先のURLを取得してリトライする必要がある
logger.warn("Redirection: code=#{response.code} message=#{response.message}")
else
logger.error("HTTP ERROR: code=#{response.code} message=#{response.message}")
end
# [エラーハンドリング]
# 各種処理で発生しうるエラーのハンドリング処理
# 各エラーごとにハンドリング処理が書けるようにrescue節は小さい単位で書く
# (ここでは全て同じ処理しか書いていない)
rescue IOError => e
logger.error(e.class)
logger.error(e.message)
logger.error(e.backtrace)
rescue TimeoutError => e
logger.error(e.class)
logger.error(e.message)
logger.error(e.backtrace)
rescue JSON::ParserError => e
logger.error(e.class)
logger.error(e.message)
logger.error(e.backtrace)
rescue => e
logger.error(e.class)
logger.error(e.message)
logger.error(e.backtrace)
ensure
logger.info("end")
end
今度これをやってみよう
https://qiita.com/toshihirock/items/19fc868d3c4c52411aa9
postがわかる気がする
faraday
https://qiita.com/YumaInaura/items/fb18e3d56dced19cbd28
http://nekorails.hatenablog.com/entry/2018/09/28/152745
使いこなせなかった
require 'faraday'
require 'json'
require 'logger'
# gem install faraday が必要
# シンプル1
# p Faraday.get("https://jsonplaceholder.typicode.com/todos/1", ssl: { verify: false })
# シンプル2
# connection = Faraday.new("https://jsonplaceholder.typicode.com/todos/1", ssl: { verify: false })
# p connection.get
# シンプル3
# connection = Faraday.new(url: "https://jsonplaceholder.typicode.com/todos/1", ssl: { verify: false })
# p connection.get
# シンプル4
connection = Faraday.new(url: "https://jsonplaceholder.typicode.com",ssl: { verify: false })
response = connection.get "/todos/1" do |request|
request.headers["Content-Type"] = "application/json"
# ssl を設定しようとしたがエラーになる
end
#p response
p response.body # レスポンスbody
result = JSON.parse(response.body)
p result
p result["userId"]
#p response.headers # レスポンスheader
#p response.status # ステータスコード
#p response.success? # リクエストは成功か?(ステータスコードが200番台か?)