- 更新日: 2014年11月6日
- Ruby
Rubyでnet/http(Net::HTTP)を使う駄目コードを書いてたので直した
Ruby の net/http(Net::HTTP) ライブラリを使って、Web API 経由の json 形式レスポンスを取得するコードを書いていたのですが、ちょっとまずい書き方をしていました。エラー処理をしっかりするように修正を行いましたのでその記録。
最初に書いてた net/http を使う駄目コード
最初に書いてた駄目コードは次のもの。Rails プロジェクトで lib 以下に作成していた自作モジュールです。
1 2 3 4 5 6 7 8 9 10 11 12 |
module SomeModule def get_sample_data url = "https://api.example.com/sample.json" uri = URI.parse(url) json = Net::HTTP.get(uri) result = JSON.parse(json) #... end #... end |
いやーこれね、駄目ですこのコード。SomeModule の get_sample_data メソッドの中で、Net::HTTP.get(uri) で uri を open して、中身の json を get するとこまで一気にやろうとしていたのですが、アクセス先サーバーが落ちてたりすると uri が開けずに例外発生。Rails の場合、500エラーを返します。
ということで、アクセス先の url が開けなかった時や、url 先がリダイレクトを繰り返していたり、Timeout になった時などのエラーハンドリングを行うように書き直しました。ほぼ以下ページの「RedirectとかTimeoutとかエラー処理とかちゃんとやりたい時用」を参考。
RubyでJSON形式の結果が返ってくるURLをParseする – Qiita
助かりました、ありがとうございます。
修正した net/http を使うコード
今回の場合 Rails プロジェクトなので、lib 以下に Web API 経由で json を get するヘルパー用のモジュールを追加しました。
lib/api_helper.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
module ApiHelper def get_json(location, limit = 10) raise ArgumentError, 'too many HTTP redirects' if limit == 0 uri = URI.parse(location) begin response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http| http.open_timeout = 5 http.read_timeout = 10 http.get(uri.request_uri) end case response when Net::HTTPSuccess json = response.body JSON.parse(json) when Net::HTTPRedirection location = response['location'] warn "redirected to #{location}" get_json(location, limit - 1) else puts [uri.to_s, response.value].join(" : ") nil end rescue => e puts [uri.to_s, e.class, e].join(" : ") nil end end end |
エラーの場合は、nil を返すようにした。
続いて、この ApiHelper#get_json メソッドを使う側、冒頭の SomeModule#get_sample_data メソッドを以下のように変更。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
module SomeModule require "api_helper" include ApiHelper def get_sample_data url = "https://api.example.com/sample.json" result = get_json(url) if result # handle json result # ... end #... end #... end |
これでエラー処理が上手くできるようになったはず。
net/http 関連で他に参考にしたページ
以下ページも大変参考になりました。
Rubyist Magazine – 標準添付ライブラリ紹介 【第 7 回】 net/http
上記るびまの記事は Net::HTTP を理解するのにとても役立ちます。Net::HTTPResponse のクラス階層が分かりやすく解説してあり、先の get_json メソッドで case response ~ と書ける理由も理解できました。Ruby の case ~ when は、=== (is_a?, kind_of?) を使ってオブジェクトの真偽を判定するのですよね。
instance method Object#===
=== (Module) – Rubyリファレンス
irb で試したところ、以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
irb(main):073:0> url = "https://api.example.com/sample.json" => "https://api.example.com/sample.json" irb(main):074:0> uri = URI.parse(url) => #<URI::HTTPS:0x007feb64843008 URL:https://api.example.com/sample.json> irb(main):075:0> response = Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http| irb(main):076:1* http.open_timeout = 5 irb(main):077:1> http.read_timeout = 10 irb(main):078:1> http.get(uri.request_uri) irb(main):079:1> end => #<Net::HTTPOK 200 OK readbody=true> irb(main):080:0> Net::HTTPSuccess === response => true irb(main):081:0> Net::HTTPRedirection === response => false irb(main):082:0> response.is_a? Net::HTTPSuccess => true irb(main):083:0> response.class => Net::HTTPOK irb(main):084:0> response.class.superclass => Net::HTTPSuccess irb(main):085:0> response.class.superclass.superclass => Net::HTTPResponse irb(main):086:0> response.class.superclass.superclass.superclass => Object |
URL をオープンするような処理では、例外のハンドリングをしっかりしておかないといけませんね。昨今のアプリケーションだと、web 経由の API を使う場面なども多いと思いますし。以上自分の書いた駄目コードを修正したエントリーでした!
- Ruby の関連記事
- Gemの作り方(Ruby Gem)
- ローカル開発中のgemをGemfileに書いてインストール
- 熊本地震の余震が夜に多いのは本当か?Rubyプログラムで検証してみた
- El Capitanでgemのnative extensionビルド失敗に対応
- Rubyで親クラスから子クラスの定数を参照
- MacabをRubyで使う
- rbenv/ruby-buildでRuby最新バージョンをインストール
- Rubyでクラスインスタンス変数にインスタンスメソッドからアクセス
- 距離1kmあたりの緯度・経度の度数を計算(日本・北緯35度)
- Google Maps Geocoding APIで住所から緯度・経度を取得するRubyコード
Leave Your Message!