FIVETEESIXONE

respondto.it


クライアントサイドの JavaScript で Form を POST する機能を書いているのですが、submit する先がまだ用意できておらずテストしにくいので、HTTP エンドポイントのテスト用サービスを使うことにしました。別に全然 RESTful な API に対しての POST とかではないものの、リクエストのパラメータが正しいかどうかなどを手っ取り早く確認できそうだったので。

HTTP エンドポイントへのテスト用サービス

HTTP エンドポイントへのテスト用のサービスはいくつかあるようですが、こちらの記事を参考に、RequestBinrespondto.it のどちらかを使ってみることにしました。今回、ちょっと外部サービスをそのまま使うのを躊躇する案件だったのと、テスト用の URL と結果をしばらく残しておきたいということがあったので、どちらもソースが公開されており、自分でローカルに立ち上げることができるのもいい感じでした。

ちょろっとソースを眺めてみると、

  • RequestBin

    Flask ベースで実装は Python

  • respondto.it

    Sinatra ベースで実装は Ruby

で、データストアはどちらも Redis を使っているようでした。ということであれば、今は Rubyist に wannabe なので当然 respondto.it を選択します。

respondto.it

ローカルへのデプロイ自体は簡単でした。やったことは、Github のリポジトリをクローンして、Gemfile などの一部の Ruby バージョンを修正したくらいで、そのまま rackup したらすんなり動いてくれました。もちろん、Redis がインストールされていなければ、先にインストールして起動しておく必要があります。

あとは、テスト用の URL を設定してアクセスすれば、こんな感じでリクエストの詳細を表示して精査することができます。

2014-11-09-respond-to-it-1.jpg

あとは、必要に応じて、データが消えないように少し弄ったりすれば、今回の目的としては十分でしょう。

JSON/XML レスポンス

今回の用途には必要ないのですが、JSON や XML をレスポンスとして設定することもできるようです。API の呼び出しを確認したいときの手軽なスタブとして利用することができそうですね。

せっかくなので試してみます。適当な JSON をレスポンスに設定して…

2014-11-09-respond-to-it-2.jpg

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 が返ってきました。んー、なんか引っかかる気もするけど、テストがないんだし何がおきてもかしくないよね。てことで一応報告しておしまい。

respondto.it doesn't return JSON and XML response