{{ currentPost.title }}
{{ currentPost.datetime }}
Rails x Grape

什麼是grape?

grape是一個用來建立API的framework,它有下面的優點:

  • 採用自己獨特的DSL來簡化建立API的流程。
  • 雖然我們也可以使用controller來建立API,但controller在啟動時會載入許多module,而其中有很多module在實作API上其實是用不到的。相較於rails的controller,使用輕量化的grape所建立的API在使用上會更有效率。
  • 內建的API版本機制與模組化的設計讓我們更容易管理維護API。
  • 支援swagger文件自動生成。

Grape on Rails

grape的一個好處是可以在rails中使用。設定的步驟如下:

  • 在Gemfile中加入grape的gem。

Gemfile

gem 'grape'
  • 在config/application.rb中設定儲放Api相關檔案的目錄,目前我們設定在app/api之下。

config/application.rb

module MyApp
  class Application < Rails::Application
    # ...
    # Support grape API
    config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb')
    config.autoload_paths += Dir[Rails.root.join('app')]
    # ...
  end
end
  • 建立一個測試用的API。

app/api/test.rb

module Api
  class Test < Grape::API
    get :ping do
      { data: "pong" }
    end
  end
end
  • 在routes中掛載api的路徑。我們將api掛載在網址/api下,這樣所有的api網址都會從/api開始。

config/routes.rb

Rails.application.routes.draw do
  # ...
  mount Api::Test => '/api'
  # ...
end
  • 重新啟動rails server,在網址列輸入localhost:3000/api/ping就可以呼叫API了。

寫測試

寫測試是非常重要的,寫api的測試更是重要。api的測試與controller非常像,都是模擬送出request後,檢查對應的回傳結果。但controller通常不會測試body的內容(因為這是屬於view的測試),而api的測試就會直接比對body輸出的結果。

  • 在rails_helper中設定api的spec存放的路徑,將所有api的spec放在spec/api下。
spec/rails_helper.rb
RSpec.configure do |config|
  # ...
  config.include RSpec::Rails::RequestExampleGroup, type: :request, file_path: /spec\/api/
  # ...
end
  • 建立Api::Test的spec:
spec/api/test_spec.rb
require 'rails_helper'

describe Api::Test do
  context 'GET /api/ping' do
    it 'should return 200 and pong data' do
      get '/api/ping'
      expect(response.status).to eq(200)
      expect(JSON.parse(response.body)).to eq({ 'data' => 'pong' })
    end
  end
end
  • 執行rspec就可以看到測試的結果嘍。
rspec spec/api/test_spec.rb

使用swagger自動生成API文件

使用grape的另一個好處是它可以自動生成swagger的API文件,所以只要API寫好了,API文件就寫好了。除此之外,還可以整合swagger-ui直接將API文件掛載在rails的routes下,超級方便的啊。下面是設定的步驟:

  • 在Gemfile中加入grape-swaggergrape-swagger-rails,基本上我們會將這兩個gem放在development的group下,因為production用不到。

Gemfile

group :development do
  gem 'grape-swagger'
  gem 'grape-swagger-rails'
end
  • API最上層的class加入add_swagger_documentation,讓grape可以自動生成swagger doc。

app/api/test.rb

module Api
  class Test < Grape::API
    get :ping do
      { data: "pong" }
    end

    if Rails.env.development?
      add_swagger_documentation(
        mount_path: 'swagger_doc',
        hide_format: true,
        hide_documentation_path: true
      )
    end
  end
end

更多有關grape-swagger的設定選項可以參考grape-swagger的文件

  • 在initializer中加入一個新檔案用來初使化grape-swagger-rails。

config/initializers/grape_swagger_rails.rb

if Rails.env.development?
  GrapeSwaggerRails.options.url = "swagger_doc"
  GrapeSwaggerRails.options.app_name = 'My App'
  GrapeSwaggerRails.options.app_url = '/api/'
end
  • 在routes中掛載api文件的路徑。

config/routes.rb

Rails.application.routes.draw do
  # ...
  if Rails.env.development?
    mount GrapeSwaggerRails::Engine => '/apidoc'
  end
  # ...
end
  • 重新啟動rails server,在網址列輸入localhost:3000/apidoc就可以看到由swagger-ui生成的API文件了。
Swagger UI
Swagger UI

小結

在這裡我們介紹了怎麼在rails中使用grape,有空再跟大家分享怎麼使用grape來建立API(這才是重點啊)。

Refs