[Ruby on Rails]Grapeを使ってWeb APIを作成する

2014.11.25

はじめに

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.

grape

簡単に纏めると

  • REST-likeなAPIのためのマイクロフレークワークである
  • Rack上で単体で、もしくはRailsやSinatraなどと組み合わせて動く
  • RESTful APIを簡単に作るためのDSL(ドメイン固有言語)である
  • と言えると思います。

    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で記述するのが良いかを検討してみるのいいかもしれません。

    参考サイト

    Grape
    Grape | API生成マイクロフレームワーク