RestClientの返り値はStringとちょっと違う

インターフェースが簡潔で使いやすいRestClientだけれども、各種HTTPメソッドの返り値をto_iするとステータスコードを返すみたいだ。

たとえば次のようなSinatraアプリが起動していたとする。

get '/' do
  "1"
end

このgetルーティングに対してRestClientでアクセスすると、次のような結果が得られる。

require "rest_client"

res = RestClient.get("http://localhost:9292/")
#=> "1"

# Stringなのにto_iはステータスコード200を返す
res.class #=> String
res.to_i  #=> 200

# to_strしても変わらない
str = res.to_str  #=> "1"
str.to_i          #=> 200
res.class         #=> String

# 期待される値はと言うと
"1".to_i  #=> 1

内部でどうやっているかまでは確認できていないけど、 このようにRestClientの返り値のto_iはステータスコードを返す。

で、具体的にどんなときに不具合があるかというと、

  • Web APIからRestClientを使って取得した値をActiveRecord::Base.findに渡す
  • 内部的にto_iしているのか、毎回id=200を探しに行く
  • json gemによるエスケープ処理JSON.generate([val])が無限ループしてしまう

ではどうやっていつものStringとして扱うのかというと、Stringで包みなおせばいい。

res = RestClient("http://localhost:9292")
str = String.new(res)
str.to_i              #=> 1
str.class             #=> String

なんでこんな変な仕様になってるんだろう。 せめて返り値には別のクラスを使用して欲しかった。

そんな感じで、RestClientは変なところではまるので要注意。