[Ruby on Rails]Grapeを使ってWeb APIを作成する
はじめに
RailsでWeb APIを作成するとき、皆さんはどのような実装を行っているでしょうか?一番多いのは、Rails標準のControllerにてリクエストを受け付け、結果をjson形式などで返すかたちだと思います。
もちろんこのような実装でも十分なのですが、今回はGrapeを使った実装を紹介したいと思います。
Grapeとは
Grapeのページにある以下の文が、その特徴をよく表していると思います。
Grape is a REST-like API micro-framework for Ruby.It's designed to run on Rack or complement existing web application frameworks such as Rails and Sinatra by providing a simple DSL to easily develop RESTful APIs.
簡単に纏めると
と言えると思います。
Rails上でGrapeを使う実装例
Grapeのページに実装例が載っているので、ほぼそのままRails上に実装してみました。以下、RailsでGrapeを実行する手順とソースです。
1.Grapeのインストール
既にRailsのプロジェクトは作成済みであるとします。Grapeの導入は簡単で、Gemfileに以下を記述してbundle installするのみです。
Gemfile
gem 'grape'
2.定義ファイル
application.rbに以下を追記し、後ほど作成するapiフォルダ内のソースを読み込むようにします。
application.rb
config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb') config.autoload_paths += Dir[Rails.root.join('app', 'api', '*')]
3.ルーティング
routes.rbに、今回作成するModuleを追加します。
routes.rb
mount Twitter::API => '/'
4.API
最後に、メインとなるAPIの処理です。上記でも書きましたが、ほぼGrapeのページからの引用で、Twitter APIを模したもののようです。一点、バージョン番号の定義のみ、引用元のソースから変更しています(3,4行目。オリジナルはコメントアウト)。
module Twitter class API < Grape::API # version 'v1', using: :header, vendor: 'twitter' version 'v1', using: :path format :json prefix :api helpers do def current_user @current_user ||= User.authorize!(env) end def authenticate! error!('401 Unauthorized', 401) unless current_user end end resource :statuses do desc "Return a public timeline." get :public_timeline do Status.limit(20) end desc "Return a personal timeline." get :home_timeline do authenticate! current_user.statuses.limit(20) end desc "Return a status." params do requires :id, type: Integer, desc: "Status id." end route_param :id do get do Status.find(params[:id]) end end desc "Create a status." params do requires :status, type: String, desc: "Your status." end post do authenticate! Status.create!({ user: current_user, text: params[:status] }) end desc "Update a status." params do requires :id, type: String, desc: "Status ID." requires :status, type: String, desc: "Your status." end put ':id' do authenticate! current_user.statuses.find(params[:id]).update({ user: current_user, text: params[:status] }) end desc "Delete a status." params do requires :id, type: String, desc: "Status ID." end delete ':id' do authenticate! current_user.statuses.find(params[:id]).destroy end end end end [/ruby]
3〜6行目で、APIのバージョン、フォーマット、プレフィックスを定義しています。8〜16行目では、helperメソッドを定義しています。18行目以降はリソースの定義となり、これらのリソースがクライアントから呼び出されることになります。
クライアントから呼び出す際のURLは、APIのバージョン、プレフィックス、リソースによって決まります。今回の例だと「http://localhost:3000/api/v1/statuses」というようになります。
リソースについて見てみると、以下のような特徴があります。
- 「desc〜」で機能の説明を記述できる
- 「get」「post」「put」「delete」と、HTTPのメソッドに対応した処理を定義できる
- 「params〜」でパラメータを定義し、「require」で必須かを定義している
最後に、上記のリソースのGet, Post, Put, Deleteをcurlで呼び出した際のコマンドを記述しておきます。
$ curl http://localhost:3000/api/v1/statuses/public_timeline $ curl http://localhost:3000/api/v1/statuses -X POST -d "status=test_string" $ curl http://localhost:3000/api/v1/statuses/5 -X PUT -d "status=test_string" $ curl http://localhost:3000/api/v1/statuses/5 -X DELETE
まとめ
リソースの書き方を見てみると、確かにDSL風に書いてあるのが分かるかと思います。Web APIを作る際には、Railsの素のControllerで行くか、DSLで記述するのが良いかを検討してみるのいいかもしれません。