Rails 環境
- Rails 6.0.0(5.2系でも同様。5.1系以下は要注意。後述。)
- Ruby 2.6.4
- Grape 1.2.4
モジュール・パスのルールがよくわからない?
Grapeの導入に関する情報は多いのですが、にもかかわらず、モジュール パスにまつわる問題に祟られて、初手から少しのサンプルコードすら動作しないことがあります。
特に、 モジュール名やパスをいきなり思い通りに設定しようとした場合、よく、Uninitialized constant
エラーが出たりします。
Place API files into app/api. Rails expects a subdirectory that matches the name of the Ruby module and a file name that matches the name of the class. In our example, the file name location and directory for Twitter::API should be app/api/twitter/api.rb.
grape公式文書の記述ですが、要はapp/api
がロードの固定的なベースになり、それ以下にあるファイル名とクラス名、ディレクトリ名とモジュール名がマッチしないといけない。例えば、Twitter::API
は、 app/api/twitter/api.rb
固定。(app/api
部は強制なので、ありがちなAPI::V1
などは、app/api/api/v1
とかapiがダブった変なパスに入れざるを得ない)。
さらに、Railsのバージョン(5.1.x以下 or 5.2.x以上)によって、Grapeとして必要な初期設定や前提が異なることも、問題を複雑化させているようです。(最後に書きます)
ここでは、不必要なものは取り除いて、階層構造もあえて最小限にします。とにかくも、動くようにします。一度動いてしまえば、あとは各種情報を参考に、トライアンドエラーで、モジュール階層やパスを自分で追加できるはずです。
設定の手順
※以降、RailsのAPIモード(rails new --api
)で作成したプロジェクトを対象にしています。
bundle exec rails --version
Rails 5.2.x
Railsバージョンに注意してください。5.1.x以前、6.x.xでも最近のものは、最後の参考情報を見てください。
Gemfileに下記を追加。
gem 'grape'
bundle install --path vendor/bundle
します。
下記のファイルを作成、または編集します。
Rails.application.routes.draw do
mount Api => '/api'
end
class Api < Grape::API
mount V1::Root
end
module V1
class Root < Grape::API
format :json
#version 'v1'
version 'v1b'
get '/' do
{ hello: 'world' }
end
end
end
確認
bundle exec rails s
でサーバを起動し、
ブラウザでhttp://localhost:3000/api/v1b
を見ます。
{"hello":"world"}
補足
Rails 5.1系以下
追加設定が必要なようです。
https://github.com/ruby-grape/grape#rails
config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb')
config.autoload_paths += Dir[Rails.root.join('app', 'api', '*')]
※上記定義のパス部分を独自に改変している例が散見されますが、互換性がなくなるので、詳しい人以外、やめたほうがいいような気はします。
Rails 6.0.0.beta2以降
'API'という識別子の利用のさい問題があり、下記の定義の追加が必要といった記述もみられるので、事の次第によっては、今後もフォローが必要かもしれません。
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.acronym 'API'
end
本例では、上記不要なはずですが、ダメな場合ご確認ください。
参考
- Grape でAPIを作るときにハマったこと
https://qiita.com/emahiro/items/6b65b2bfe6878a63b3c0
以 上。