Rails + Grapeを使って超単純なapiを作ってみる
初心者の勉強記録です。
「〜らしい」や「っぽい」などの語尾が多くなっています。
手順を書き残すため、主題とは外れた内容も含みます。
間違ったり知識が最新でなかったりすると思いますのでツッコミ大歓迎でございます。
Railsとgrapeを組み合わせる利点はあるのか
いい感じの形式を強制されるので、一度導入すれば後で拡張と保守が楽になりそう
Grape公式サイト
monterail.com
本家のサンプルリポジトリ
rails-grape-example/app at master · monterail/rails-grape-example · GitHub
参考サイト
grapeメモ - Qiita ← ここのサイトさまを見ながら作りますm(_ _)m
[Ruby on Rails]Grapeを使ってWeb APIを作成する | DevelopersIO
http://qiita.com/magaya0403/items/f9cd1340960ab997cf63
http://qiita.com/takusemba/items/a86796aa3c207155c579
公式サイトを拾い読みメモ
・APIバージョンをパスに含める構造を取る
・APIに関するコードベースをAPIモジュール配下に設置する
・format は:jsonが推奨されているらしく、xmlは
# We don't like xml anymore とか言われているが使用不可かどうかまでは調べてない
Controllerの定義は次のような形式になる
# app/controllers/api/v1/hussars.rb module API module V1 class Hussars < Grape::API version 'v1' # path-based versioning by default format :json # We don't like xml anymore resource :hussars do desc "Return list of hussars" get do Hussar.all # obviously you never want to call #all here end end end end end
このコードだとクライアントから呼び出すパスは/v1/hussars.jsonで終わる
/v1/wings.json で終わるパスであればクラスの定義は↓になる。
API::V1::Wings → app/controllers/api/v1/wings.rb
/v2/hussars.json なら
API::V2::Hussars → app/controllers/api/v2/hussars.rb
各APIバージョンについて、すべてのリソースをマウントする集約クラスが必要。
# app/controllers/api/v1/base.rb module API module V1 class Base < Grape::API mount API::V1::Hussars mount API::V1::Wings end end end
v2だと app/controllers/api/v2/base.rb.
すべてのAPIバージョンを集約するクラスが1つ必要。
# app/controllers/api/base.rb module API class Base < Grape::API mount API::V1::Base mount API::V2::Base end end
最後に集約クラスをroutes.rbに記述する
# config/routes.rb Monterail::Application.routes.draw do # ... mount API::Base => '/api' # ... end
config/application.rbを編集
config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb') config.autoload_paths += Dir[Rails.root.join('app', 'api', '*')]
APIクラスを設置する(リソースを集約したクラスでもある)
class API < Grape::API prefix 'api' version 'v1', using: :path format :json helpers do def dummy_code { code: 1 } end def err401 error!('401 Unauthorized', 401) end end resource :dummy_api do get :status do dummy_code end get :secret do err401 end end end
rake routesと実行すると次のように表示される。Controllerのルーティングと違う。
$ rake routes Prefix Verb URI Pattern Controller#Action api / API
このサイト様によると
・「desc〜」で機能の説明を記述できる
・「get」「post」「put」「delete」と、HTTPのメソッドに対応した処理を定義できる
・「params〜」でパラメータを定義し、「require」で必須かを定義している
プライベートメソッドはhelpers内で行うことになっているらしい
検証
ローカルサーバーを立ち上げる
$ rails s
curlコマンドで確認する
$ curl localhost:3000/api/v1/dummy_api/status
{"code":1}
目論見どおり文字列が返ってくる
サーバーにデプロイする
herokuのアカウントを持っているのでそこにデプロイ
$ heroku login
$ heroku create sakurabird1-grape-example
Creating ⬢ sakurabird1-grape-example... done
https://sakurabird1-grape-example.herokuapp.com/ | https://git.heroku.com/sakurabird1-grape-example.git
$ git push heroku master
このようなエラーメッセージが出るので
remote: Make sure that `gem install sqlite3 -v '1.3.12'` succeeds before bundling. remote: ! remote: ! Failed to install gems via Bundler. remote: ! remote: ! Detected sqlite3 gem which is not supported on Heroku. remote: ! https://devcenter.heroku.com/articles/sqlite3 remote: ! remote: ! Push rejected, failed to compile Ruby app.
group :development, :test do # Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'byebug' gem 'sqlite3' end group :production do gem 'pg’ end
$ bundle install ←記述後に実行しておく
変更をcommitした後、最新のコードをHerokuにpush
$ git push heroku master
デプロイ成功
remote: https://sakurabird1-grape-example.herokuapp.com/ deployed to Heroku
URLはこうなる
https://sakurabird1-grape-example.herokuapp.com/api/v1/dummy_api/status
検証
$ curl https://sakurabird1-grape-example.herokuapp.com/api/v1/dummy_api/status
と実行すると
{"code":1}
とレスポンスが返ってくるので成功