Railsを使ったAPI開発者のあなたはきっとこう考えたことがあるはずです。
「既にあるAPIを使えればテストも書いてあるから新規にモジュールを作るより楽できそうだなぁ。でもHTTPでリクエストするのは処理時間的にきついなぁ。HTTPを経由しないでリクエストできないかなぁ。。だって自分に対してHTTPとかわけわかんなくない?」
奥さんできますよ!
コード
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してあげればいいのですが、三つのポイントがあります。
- ヘッダー名は全て大文字にする
- ヘッダー名に
'HTTP_'
という接頭辞を付ける - ヘッダー名のハイフンはアンダースコアに置き換える
例
header_hash = {
'REQUEST_METHOD' => 'POST',
'HTTP_USER_TOKEN' => user_token,
}
上記の例ではアプリとしてuser_token
という独自ヘッダーを定義しているという仮定で、上記の三つのポイントを踏まえheaders_hashを作っています。
ただし・・・
一応動作確認した限りは問題なさそうなのですが、先例が殆ど無いので怖くて使っていません。。
mockという名前が付いているので心配になってproductionでも試しましたがちゃんと動きました。
使った方ご報告下さると助かります!
参考
Codewall - Rails - Internal Requests (Example)
Qiita - RackアプリケーションのエンドポイントをHTTPを経由せずに呼び出す方法