Rails:HTTPを使わずに自身のAPIを独自ヘッダー付きでリクエストできて感動する方法

Railsを使ったAPI開発者のあなたはきっとこう考えたことがあるはずです。

「既にあるAPIを使えればテストも書いてあるから新規にモジュールを作るより楽できそうだなぁ。でもHTTPでリクエストするのは処理時間的にきついなぁ。HTTPを経由しないでリクエストできないかなぁ。。だって自分に対してHTTPとかわけわかんなくない?」

奥さんできますよ!

コード

my_app/lib/internal_api_client

module InternalApiClient

  def self.request(headers_hash, internal_endpoint, params = nil)
    params = params.to_query if params.present?
    hash = Rack::MockRequest.env_for(internal_endpoint, params: params)

    # 何も指定していないと"REQUEST_METHOD"=>"GET"になる
    pp hash

    # headers_hashをmergeして追加する
    hash.merge!(headers_hash)

    # この中身が肝心
    pp hash

    # リクエストを投げる!
    res = Rails.application.routes.call(hash)

    # resの中身はこんな感じで取れます
    pp res[0]      # status
    pp res[1]      # headers
    pp res[2].body # body

    JSON.parse(res[2].body)
  end
end

使い方

rails consoleからすぐに使えます。
internal_endpointに渡すURL文字列にはhttp://は不要です。内部だから関係ないという事なんでしょうね。

[foo@bar my_app]$ rails c
Running via Spring preloader in process 21427
Loading development environment (Rails 5.0.2)
[1] pry(main)> require "#{Rails.root}/lib/internal_api_client"
=> true
[2] pry(main)> headers_hash = { 'REQUEST_METHOD' => 'POST'}
=> {"REQUEST_METHOD"=>"POST"}
[3] pry(main)> InternalApiClient.request(headers_hash, 'users')
=>諸事情によりお見せできません

ぜひ実際に動かしてHTTPを使わないという感動を味わっていただきたいです。

と、ここまできて、読んでいただいている方の中には既に試したことがあり、独自ヘッダーの指定方法がわからずに断念した方もいらっしゃるのではないでしょうか?

奥さんできますよ!

独自ヘッダーを指定する方法

Rack::MockRequest.env_forの戻り値のハッシュに独自ヘッダーもmergeしてあげればいいのですが、三つのポイントがあります。

  1. ヘッダー名は全て大文字にする
  2. ヘッダー名に'HTTP_'という接頭辞を付ける
  3. ヘッダー名のハイフンはアンダースコアに置き換える

header_hash = {
  'REQUEST_METHOD' => 'POST',
  'HTTP_USER_TOKEN' => user_token,
}

上記の例ではアプリとしてuser_tokenという独自ヘッダーを定義しているという仮定で、上記の三つのポイントを踏まえheaders_hashを作っています。

ただし・・・

一応動作確認した限りは問題なさそうなのですが、先例が殆ど無いので怖くて使っていません。。
mockという名前が付いているので心配になってproductionでも試しましたがちゃんと動きました。

使った方ご報告下さると助かります!

参考

Codewall - Rails - Internal Requests (Example)
Qiita - RackアプリケーションのエンドポイントをHTTPを経由せずに呼び出す方法

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.