クライアントサイドの JavaScript で Form を POST する機能を書いているのですが、submit する先がまだ用意できておらずテストしにくいので、HTTP エンドポイントのテスト用サービスを使うことにしました。別に全然 RESTful な API に対しての POST とかではないものの、リクエストのパラメータが正しいかどうかなどを手っ取り早く確認できそうだったので。
HTTP エンドポイントへのテスト用サービス
HTTP エンドポイントへのテスト用のサービスはいくつかあるようですが、こちらの記事を参考に、RequestBin か respondto.it のどちらかを使ってみることにしました。今回、ちょっと外部サービスをそのまま使うのを躊躇する案件だったのと、テスト用の URL と結果をしばらく残しておきたいということがあったので、どちらもソースが公開されており、自分でローカルに立ち上げることができるのもいい感じでした。
ちょろっとソースを眺めてみると、
-
RequestBin
Flask ベースで実装は Python
-
Sinatra ベースで実装は Ruby
で、データストアはどちらも Redis を使っているようでした。ということであれば、今は Rubyist に wannabe なので当然 respondto.it を選択します。
respondto.it
ローカルへのデプロイ自体は簡単でした。やったことは、Github のリポジトリをクローンして、Gemfile などの一部の Ruby バージョンを修正したくらいで、そのまま rackup
したらすんなり動いてくれました。もちろん、Redis がインストールされていなければ、先にインストールして起動しておく必要があります。
あとは、テスト用の URL を設定してアクセスすれば、こんな感じでリクエストの詳細を表示して精査することができます。
あとは、必要に応じて、データが消えないように少し弄ったりすれば、今回の目的としては十分でしょう。
JSON/XML レスポンス
今回の用途には必要ないのですが、JSON や XML をレスポンスとして設定することもできるようです。API の呼び出しを確認したいときの手軽なスタブとして利用することができそうですね。
せっかくなので試してみます。適当な JSON をレスポンスに設定して…
Accept: application/json
を設定して curl でアクセスしてみます。
$ curl -v -H "Accept: application/json" http://localhost:9292/test
Howdy
結果は、この通り設定した JSON が返って…きてない!きてないじゃん!!Howdy って言われてるだけじゃん!!!
何がおかしいんだろう?
テストを見てみる
機能の動きがよくわからないとき、テストを見てみるのが近道なことが多いです。仕様に対する実行サンプルになりますからね。なので、えーと、テスト、テストはどこかな、と。
テストはありませんでした。そのかわりに、Rakefile
にとてもナイスなコメントが書いてあります。
task :default do
puts "I am a horrible person for not having tests yet."
end
「テストを見てみる」案は頓挫しました。ということで、プロダクションコードを見てみるしかなさそうです。
JSON レスポンスの判定
JSON レスポンスを返す判定は、 app.rb
の中で以下のようにチェックされています。Howdy が返ってきちゃってるということは、この判定が期待通りに動いていないということですね。
if json?
json
elsif xml?
xml
else
"Howdy"
end
じゃあこの json?
メソッドがどう判定しているかというと…
def json?
request.accept.first == "application/json" || params[:format] =~ /json/i
end
このようにチェックしているようです。XML の場合でも同様です。うーん、今回は curl のリクエストで HTTP ヘッダに application/json
を設定しているはずなんですが。
って、この request.accept.first
は一体どんな内容なんでしょうか。とりあえずその中身とクラスを見てみると…
p request.accept.first
#=> #<Sinatra::Request::AcceptEntry:0x007fccdeb58d50 @entry="application/json", @type="application/json", @params={}, @q=1.0>
p request.accept.first.class
#=> Sinatra::Request::AcceptEntry
うん、request.accept.first == "application/json"
が true
になる気が全然しない。もしそうなるとすれば、それは Sinatra::Request::AcceptEntry
で ==
が再定義されていて、その内部で to_s
か何かをやってるということでしょうか?でも実際に期待通りに true
を返していないところからすると、そういうことでもないっぽい。バグなのかなー。
ひとまずコードを書き換えて、
def json?
request.accept.first.to_s == "application/json" || params[:format] =~ /json/i
end
とするとちゃんと JSON が返ってきました。んー、なんか引っかかる気もするけど、テストがないんだし何がおきてもかしくないよね。てことで一応報告しておしまい。