前の記事([Sinatra] シンプルな JSON API サーバーを作る)で非常に簡単な API サーバーを作ったが、そこに少し手を加えてより実用的にしてみたい。
おしながき
- POST でデータを登録できるようにする
- Rspec でテストする
- データを JSON Schema でバリデーションする
POST でデータ登録
まずは前回と同様に GET でデータベースアクセスできるところまで持っていく。
bundler で gem を入れるが、今回は mysql でやるので activerecord
とmysql2
を入れる。
# Gemfile |
db/database.rb
と db/database.yml
を用意する。
# database.rb |
default: |
今回は database.yml で接続環境毎に設定を分け、SINATRA_ENV
環境変数で切り替えるようにした。開発環境ではexport SINATRA_ENV=development
としている。
ソケットの罠
index.rb
を作成し、実行したうえでhttp://localhost:4567/books/1にアクセスする。
# index.rb |
しかしアクセスすると以下のエラーになった。
※ 実際開発していた API サーバーでのキャプチャなので、アドレスが違うのは勘弁してホシイ
今回開発環境用の DB として docker で mysql サーバーをローカルに立てていた。しかし mysql2 はソケット接続しようとしていてエラーになっているらしい。解決策はここ(Ruby On Rails で MySQL の Socket エラーが出た時は素直に localhost を 127.0.0.1 に直すのが一番いいと思う)にある通り、接続先をlocalhost
から127.0.0.1
に変更することで対応した。
development: |
これで正常にアクセスできることは確認できた。
Hash とシンボルの罠
続いて POST メソッドを追加していく、こんな感じかな
post '/books', provides: :json do |
ところがここにデータを POST すると 500 エラーになる
curl -v -H "Content-type: application/json" -X POST -d '{"title":"すごいHaskellたのしく学ぼう!","author":"Miran Lipovaca","pages":391}' http://localhost:4567/books/ |
原因は params[:title]
などが nil になることだった。「Hash のキーはシンボルと文字列を区別する」というすごい単純なオチだったんだけど、ここ(Hash から文字列でもシンボルでも値を取り出す)を参考にシンボルのまま取り出せるようにしてみる。
params = JSON.parse request.body.read |
を
params = JSON.parse(request.body.read).with_indifferent_access |
にするだけで正常に登録されるようになった。
ちなみに with_indifferent_access
は本来 active_support
と active_support/core_ext
を require しなければ呼べないが、今回は特に意識することなく呼ぶことができている。
事前に ActiveRecord::Base.configurations
を実行しているのだが、(たぶん)この中で active_support
を require しているので、後続の処理では明示的に active_support
を require しなくても with_indifferent_access
を呼ぶことができる。
実行環境
- Ruby 2.3.3
- Sinatra 2.0.3
- activerecord 5.2.0
- mysql2 0.5.1