Grape middlewareの作り方

Grape
-----

[Grape]()は、RESTFulなAPIサーバを作るためのRubyベースフレームワークです

私が作るRESTFulなAPIサーバは、たいてい[ruby-grape]()を使っています

利点は[Sinatra]()のような軽さで小さく作ることもできるし、parameter validationやdescriptionがDSLで実装されてたり、[grape-entity]()のようなモデルも実装できるのでカッチリと作るのにも適しています

最小コードはこんな感じ

```rb:config.ru
require "grape"

class ExampleAPI < Grape::API
  format :json
  prefix :api

  desc "Return current localtime. endpoint is /api/now"
  get "/now" do
    {now: Time.now.to_s}
  end

  desc "Return for your input as echo. endpoint is /api/echo"
  post "/echo" do
    {your_input: params}
  end
end

run ExampleAPI
```

```console
$ curl -w "\n" localhost:9292/now
{"now":"2016-05-11 08:21:21 +0900"}
$ curl -w "\n" -d k=v -X POST localhost:9292/echo
{"your_input":{"k":"v"}}
```

Grape middleware
----------------

規模が大きくなってくると、ログや認証を実装することになりますが、その時覚えておきたいのが Grape middleware です
Rack middleware と概念や実装は同じです

Grape middlewareの実装アプローチは2つのうち、どちらかになります

1. `#after` を持ったクラス ( `#before` でもいいけど) => サンプルの `Modifying`
2. `#initialize(app)` と `#call(env)` を持ったクラス => サンプルの `Monitoring`

responseやrequestに対してなにか行うなら１が、メソッド自体の呼び出しも制御したい※なら２がおすすめです

※たとえばメソッド呼び出しが何秒かかったか？といったモニタリング用途

論よりコード
------------

先の最小コードに２つ処理を加えます

1. response bodyのhashに値を加える => Modifyingクラス
2. メソッド呼び出しのベンチマーク => Monitoringクラス

```rb:config.ru
require "grape"
require "benchmark"

class Modifying < ::Grape::Middleware::Base
  def after
    puts "Run at Modifying middleware"
    # U can ref: @env, @app, @options, @app_response
    body = JSON.parse(@app_response.body.first)
    body["modifying"] = "add by Modifying"
    [201, { 'Content-Type' => "application/json" }, [body.to_json]]
  end
end

class Monitoring < ::Grape::Middleware::Base
  def initialize(app)
    @app = app
  end
  def call(env)
    puts "Run at Monitoring middleware"
    tms = Benchmark.measure {
      @app_response = @app.call(env)
    }
    p tms
    @app_response
  end
end

class ExampleAPI < Grape::API
  format :json
  prefix :api

  use Modifying
  use Monitoring

  desc "Return current localtime. endpoint is /api/now"
  get "/now" do
    {now: Time.now.to_s}
  end

  desc "Return for your input as echo. endpoint is /api/echo"
  post "/echo" do
    puts "Execute POST /echo"
    {your_input: params}
  end
end

run ExampleAPI
```

```console
$ curl -w "\n" localhost:9292/api/v1/now
{"now":"2016-05-11 08:21:21 +0900","modifying":"done"}
--- Log: Monitoring => Modifying
Run at Monitoring middleware
Run at Modifying middleware
#<Benchmark::Tms:0x005596c64a9ce8 @label="", @real=0.006959942000321462, @cstime=0.0, @cutime=0.0, @stime=0.0, @utime=0.010000000000000009, @total=0.010000000000000009>
127.0.0.1 - - [11/May/2016:08:22:36 +0900] "GET /api/v1/now HTTP/1.1" 201 - 0.0418
---

$ curl -w "\n" -d k=v -X POST localhost:9292/api/v1/echo
{"your_input":{"k":"v"},"modifying":"done"}
--- Log: Monitoring => Modifying
Run at Monitoring middleware
Execute POST /echo
Run at Modifying middleware
#<Benchmark::Tms:0x005596c6436450 @label="", @real=0.0025449659988225903, @cstime=0.0, @cutime=0.0, @stime=0.0, @utime=0.010000000000000009, @total=0.010000000000000009>
127.0.0.1 - - [11/May/2016:08:23:06 +0900] "POST /api/v1/echo HTTP/1.1" 201 - 0.0037
---
```

あとがき
--------

すまん、力尽きた。需要があればコード解説しますので、コメントください