[youRoom][api][oauth] RubyのOAuth gemでネストしたパラメータを利用するときはご用心

youRoomのAPIは、Railsの画面の機能をそのまま使うことを前提としているためパラメータが若干複雑です。

たとえば、記事のcreateのパラメータは

entry[content]=本文&entry[parent_id]=3

というようにネストした形のパラメータとなっています。

要望に応じて変更する可能性はありますが、現在はサーバ側が簡単にできるためこんな風になっています。

このAPIに対して、RubyのOAuth gemからリクエストを送信する場合、最初は以下のようなパラメータを渡していました。

access_token.post(:post, "https://r6.youroom.in/entries.json", {:entry => {:content => "本文", :parent_id => 3}})

このようにハッシュでパラメータを引数として渡せると、直感的ですよね?僕はそう思います。
しかし、これだとサーバ側では、

entry=content本文parent_id3

というパラメータとして検出されてしまうのです。これを解決するためにまずはこのようにしてみました。

access_token.post(:post, "https://r6.youroom.in/entries.json", {:entry => {:content => "本文", :parent_id => 3}}.to_query)

to_queryとすると文字列になりbodyに含まれます。こうすることで正しくサーバ側でネストしたパラメータが取得されました。

しかし、これでは他の問題がさらに発生します。クライアント側ではパラメータを文字列で渡しているためOAuthの署名の文字列に含まれませんが、サーバ側では、bodyを解析してパラメータとなっているので、OAuthの署名の文字列に含まれます。これによって署名が正しくないと判定され認証が通過出来ませんでした。

どうも手がなくなってしまい、 id:pochi_black さんが作ってくれたyouRoomのAPIのgemを見ていると、パラメータをoptimizeしているのを発見しました。何をしているかというと、

{:entry => {:content => "本文", :parent_id => 3}} => {"entry[content]" => "本文", "entry[parent_id]" => "3"}

というように変換しているのです。なるほど確かにこれであれば、署名もうまく通りそうです。僕はこんな感じで実装してみました。
ちなみに、youroom_apiのgemはこちら http://github.com/pochi/youroom_api

param = {:entry => {:content => "本文", :parent_id => 3}}
Hash[URI.decode(param.to_query).split('&').map{|item|item.split('=')}] # => {"entry[content]" => "本文", "entry[parent_id]" => "3"}

OAuthのgemでネストしたパラメータを送る際は、ちょっと工夫が必要ですのでご注意を。