LoginSignup
175
168

More than 5 years have passed since last update.

[Rails4] Grape で API を簡単に実装 & API を複数バージョンで分ける方法

Posted at

Grape を利用すると Restful な WEB-API が簡単に作成できるらしいので試してみました。その際、実際の運用を視野にいれて、次のこともやってみました。

  • 複数の API バージョン に対応する。
    • 例:http://ドメイン/api/v1/.. http://ドメイン/api/v2/..
  • 1つのソースがファットにならないよう モデル毎にソースを分ける

まずは Grape の導入手順から説明します。

Grape の導入手順

前提

  • 手元の OS:Mac OS X 10.9.5 (Mavericks)
  • Ruby:2.1.2
  • Rails:4.1.1

Grape は結果、0.9.0 が入りました。

手順

  • 適当な Rails プロジェクトを作成。

    $ bundle exec rails new grape_app --skip-bundle -T
    
  • Gemfile への追記。

    Gemfile
    #..
    
    gem 'grape'
    
    #..
    
  • gem をインストール。

    $ cd grape_app
    $ bundle install --path vendor/bundle
    

API の作成

前提

APIのソースコードは app/apis/ 下に置くこととします。ファイル構成はこんな感じ。

スクリーンショット 2014-10-09 17.47.13.png

ディレクトリ構成およびファイル名は、クラスの名前空間およびクラス名と一致させる必要があります。 大文字/小文字は、気にしなくてもいいみたい。

手順

  • 適当に Scaffold します。

    $ ./bin/rails g scaffold person name:string age:integer memo:text
    $ ./bin/rails g scaffold product name:string price:integer memo:text
    $ ./bin/rake db:migrate
    

    Person モデルと Product モデルが作られます。

  • app/apis/ 下の Ruby ファイルが読み込まれるようにします。

    config/application.rb
    #..
    
    module GrapeApp
      class Application < Rails::Application
        #..  
    
        config.paths.add File.join('app', 'apis'), glob: File.join('**', '*.rb')
        config.autoload_paths += Dir[Rails.root.join('app', 'apis', '*')]
      end
    end
    
  • 基底となるAPIクラスを作成します。

    • このファイルで各バージョンのAPIをマウントします(今回は、バージョン1のみ)。
    app/apis/api/root.rb
    module API
      class Root < Grape::API
        # http://localhost:3000/api/
        prefix 'api'
    
        mount API::Ver1::Root
        #mount API::Ver2::Root
      end
    end
    
  • バージョン1の中で、基底となるAPIクラスを作成します。

    • ここで 各APIの実体をマウントします。
    app/apis/api/ver1/root.rb
    module API
      module Ver1
        class Root < Grape::API
          # http://localhost:3000/api/v1/
          version 'v1'
          format :json
    
          mount API::Ver1::People
          mount API::Ver1::Products
        end
      end
    end
    
  • 各APIの実体を作成します。

    • 今回は「全件取得」と「1件取得」のAPIを作成します。
    app/apis/api/ver1/people.rb
    module API
      module Ver1
        class People < Grape::API
          resource :people do
    
            # GET /api/v1/people
            desc 'Return all people.'
            get do
              Person.all
            end
    
            # GET /api/v1/people/{:id}
            desc 'Return a person.'
            params do
              requires :id, type: Integer, desc: 'Person id.'
            end
            get ':id' do
              Person.find(params[:id])
            end
          end
        end
      end
    end
    
    app/apis/api/ver1/products.rb
    module API
      module Ver1
        class Products < Grape::API
          resource :products do
    
            # GET /api/v1/products
            desc 'Return all products.'
            get do
              Product.all
            end
    
            # GET /api/v1/products/{:id}
            desc 'Return a product.'
            params do
              requires :id, type: Integer, desc: 'Product id.'
            end
            get ':id' do
              Product.find(params[:id])
            end
          end
        end
      end
    end
    
  • 最後に、基底となるAPIクラスをルーティングに追加します。

    config/routes.rb
    Rails.application.routes.draw do
    #..
    
      mount API::Root => '/'
    
    #..
    end
    

動作確認

適当にデータを登録し、ブラウザでアクセスしてみます。

screen1 copy.png screen2 copy.png

screen3 copy.png screen4 copy.png

おわりに

簡単に API が作成できました。自身の課題として、次のものがあります。

  • Grape の GitHubページ に記載されている機能を検証できていない
  • エラーのハンドリングまわりの実装
  • JSONデータの入れ子に対応できるよう、テンプレートエンジンを導入(rabl が良い?)

今回はわりとよい感触を得られたので、引き続き触って評価してみようと思います。

175
168
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
175
168