これ何
API Clientを作っていた時にresponseを抽象化したclassを作りたかった。その作業メモ
問題
例えば、モンスターを扱うAPIがあったとする。
API Clientは返って来たデータをMonster classで扱いたいはずだ。
class Monster
def initialize(name:, power:, hp:)
@name = name; @power = power; @hp = hp
end
end
そして、次のようなApiClientを利用しているとする。
すると、Monster classを利用すると、ArgumentErrorになってしまう。
Class ApiClient
def initialize
@conn = Faraday.new(:url => 'url')
@base = 'api/v1/'
@token = ENV['TOKEN']
end
def get
@conn.post "#{@base}monster", {token: @token}.to_json
monsters = JSON.parse(response.body)
monsters.each do |monster|
Monster.new(monster)
# => ArgumentError: wrong number of arguments (given 1, expected 0)
end
end
end
原因
なぜArgumentErrorを起こすのだろうか?
理由は簡単で、initializeしようとしているargumentを見るとわかる。
次のようなstring hashになっているため、keyward引数として渡すことができないのである。
{
"name": "gerugeru",
"power": 100,
"hp": 70
}
解決策
どうすれば良いか、原因は先ほど述べたようにstring hashになっているため、引数に出来なのである。
返ってきた値をJSON.parseする時にsymbol hashにすれば、keyword引数を渡すことができ、instanceを作成することができる。
JSON.parseの引数に、 symbolize_names: true
とすることでsymbol hashを扱うことができる
monsters = JSON.parse(response.body, symbolize_names: true)
# => {
# :name => "gerugeru",
# :power => 100,
# :hp => 70
# }
この結果initializerにsymbol hashを渡すことができ、めでたくレスポンスをinstanceとして作成することができた。