LoginSignup
62
62

More than 5 years have passed since last update.

Rails API 使ってみた

Posted at

昨日 Ginza.rb 第23回 APIのみのRailsアプリ「Rails API」を読もう! で Ginza.rb に初参加してきたので復習メモ。

ちなみに Ginza.rb は二周年だそうですよ。おめでとうございます!

Ginza.rb の内容は Rails5 でとりこまれることが決まって目下議論中らしい Rails API についてのコードリーディングでした。

まだ Rails 本体にマージされていないので、普通の rails と rails-api で比較しながら使ってみました。

アプリ作成

$ gem install rails-api
$ rails new blog_app # 普通の rails
$ rails-api new blog_api # API な rails

middleware 比較

Rails API は使用している middleware を単に減らしているだけぽかった。比較してみる。

blog_app$ ./bin/rake middleware > app.middleware
blog_api$ ./bin/rake middleware > api.middleware
app_api.diff
1d0
< use Rack::Sendfile
4c3
< use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x007fa99ccebcb8>
---
> use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x007f5618cc2200>
6d4
< use Rack::MethodOverride
10d7
< use WebConsole::Middleware
18,20d14
< use ActionDispatch::Cookies
< use ActionDispatch::Session::CookieStore
< use ActionDispatch::Flash
25c19
< run BlogApp::Application.routes
---
> run BlogApi::Application.routes

Rails API 側で追加の middleware はなさそう。

Scaffold 追加

Entry という title, body を持つモデルを追加してみる。

blog_app$ ./bin/rails g scaffold entry title:string body:text
- snip 5 lines -
      create      test/fixtures/entries.yml
      invoke  resource_route
       route    resources :entries
      invoke  scaffold_controller
- snip 23 lines -

blog_api$ ./bin/rails g scaffold entry title:string body:text
- snip 5 lines -
      create      test/fixtures/entries.yml
      invoke  api_resource_route
       route    resources :entries, except: [:new, :edit]
      invoke  scaffold_controller
- snip 3 lines -

コードリーディング通り view(erb, jbuilder), helper, assets なんかが生成されず api_resource_route が invoke されて :new, :edit が生成されていないことが確認できた。

GET

Entry を一個追加して GET してみる。

blog_app$ ./bin/rails s -p 3000
$ curl http://localhost:3000/entries.json
[{"id":1,"title":"title","body":"body","url":"http://localhost:3000/entries/1.json"}]

blog_api$ ./bin/rails s -p 3001
$ curl http://localhost:3001/entries
[{"id":1,"title":"title","body":"body","created_at":"2015-05-XXTXX:XX:XX.XXXZ","updated_at":"2015-05-XXTXX:XX:XX.XXZ"}]

Rails APP はタイムスタンプがなく url というのが追加されてた。

ちなみにそれぞれのログが

# blog_app
Started GET "/entries.json" for 127.0.0.1 at 2015-05-XX XX:XX:XX +0900
Processing by EntriesController#index as JSON
  Entry Load (0.2ms)  SELECT "entries".* FROM "entries"
  Rendered entries/index.json.jbuilder (1.3ms)
Completed 200 OK in 3ms (Views: 2.7ms | ActiveRecord: 0.2ms)

# blog_api
Started GET "/entries" for 127.0.0.1 at 2015-05-XX XX:XX:XX +0900
Processing by EntriesController#index as */*
  Entry Load (0.2ms)  SELECT "entries".* FROM "entries"
Completed 200 OK in 1ms (Views: 1.0ms | ActiveRecord: 0.2ms)

となっていて Rails API は jbuilder で render してないことが確認できた。その分速い。

ベンチマーク

$ ab -n 1000 -c 10 http://localhost:3000/entries.json
$ ab -n 1000 -c 10 http://localhost:3001/entries
Rails APP Rails API
Server Software WEBrick/1.3.1 WEBrick/1.3.1
Server Hostname localhost localhost
Server Port 3000 3001
Document Path /entries.json /entries
Document Length(bytes) 85 120
Concurrency Level 10 10
Time taken for tests(seconds) 10.160 7.085
Complete requests 1000 1000
Failed requests 0 0
Total transferred(bytes) 539000 575000
HTML transferred(bytes) 85000 120000
Requests per second([#/sec] (mean)) 98.42 141.14
Time per request([ms] (mean)) 101.604 70.851
Time per request([ms] (mean, across all concurrent requests)) 10.160 7.085
Transfer rate([Kbytes/sec] received) 51.81 79.25

Requests per second で比較すると Rails API の方が 1.43 倍くらい速いことが確認できた。

Rails APP で jbuilder 使わない

APP 側で jbuilder での render を止めてみて再度ベンチマークとってみる。

  def index
    @entries = Entry.all

    respond_to do |format|
      format.html
      format.json { render json: @entries.to_json, status: 200 and return }
    end
  end

curl してみる。

$ curl http://localhost:3000/entries.json
[{"id":1,"title":"title","body":"body","created_at":"2015-05-XXTXX:XX:XX.XXZ","updated_at":"2015-05-XXTXX:XX:XX.XXXZ"}]

url がなくなって Rails API の結果と要素が同じになった。
ログを確認してみる。

Started GET "/entries.json" for 127.0.0.1 at 2015-05-XX XX:XX:XX +0900
Processing by EntriesController#index as JSON
  Entry Load (0.2ms)  SELECT "entries".* FROM "entries"
Completed 200 OK in 2ms (Views: 0.1ms | ActiveRecord: 0.2ms)

jbuilder の render がなくなったのが確認できたので、再度ベンチマークとってみた。

Rails APP w/o jbuilder Rails API
Server Software WEBrick/1.3.1 WEBrick/1.3.1
Server Hostname localhost localhost
Server Port 3000 3001
Document Path /entries.json /entries
Document Length(bytes) 120 120
Concurrency Level 10 10
Time taken for tests(seconds) 8.389 7.085
Complete requests 1000 1000
Failed requests 0 0
Total transferred(bytes) 575000 575000
HTML transferred(bytes) 120000 120000
Requests per second([#/sec] (mean)) 119.20 141.14
Time per request([ms] (mean)) 83.894 70.851
Time per request([ms] (mean, across all concurrent requests)) 8.389 7.085
Transfer rate([Kbytes/sec] received) 66.93 79.25

ちょっと速くなった。

結論

「初参加の方から一言」通り、やっぱり

RailsAPI使わないかもしれない…

というよりは Rails APP w/o jbuilder で十分な気がしなくもない。

pull request の中でシリアライズに active_model_serializers をデフォルトで使用するみたいなことが議論されている?ので本体に正式にマージされたら、あらためてベンチマークをとってみたいと思います。

適当にでっちあげた投稿(次回の Ginza.rb のネタ?)なので、間違いとかあれば指摘していただけると助かります。

62
62
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
62
62