class ApiValve::Forwarder

This class is responsible for forwarding the HTTP request to the designated endpoint. It is instantiated once per Proxy with relevant options, and called from the router.

Public Class Methods

new(options = {}) click to toggle source

Initialized with global options. Possible values are: request: Options for the request wrapper. See Request#new. response: Options for the response wrapper. See Response#new

# File lib/api_valve/forwarder.rb, line 15
def initialize(options = {})
  @options = options.with_indifferent_access
  uri = URI(options[:endpoint])
  # Target prefix must be without trailing slash
  @target_prefix = uri.path.gsub(%r{/$}, '')
end

Public Instance Methods

call(original_request, local_options = {}) click to toggle source

Takes the original rack request with optional options and returns a rack response Instantiates the Request and Response classes and wraps them around the original request and response.

# File lib/api_valve/forwarder.rb, line 25
def call(original_request, local_options = {})
  request = build_request(original_request, request_options.deep_merge(local_options))
  response = build_response(original_request, run_request(request), response_options)
  response.rack_response
end

Private Instance Methods

build_request(original_request, options) click to toggle source
# File lib/api_valve/forwarder.rb, line 33
def build_request(original_request, options)
  klass = options[:klass] || Request
  klass.new(original_request, options)
end
build_response(original_request, original_response, options) click to toggle source
# File lib/api_valve/forwarder.rb, line 38
def build_response(original_request, original_response, options)
  klass = options[:klass] || Response
  klass.new(
    original_request,
    original_response,
    options.merge(
      target_prefix: @target_prefix,
      local_prefix:  original_request.env['SCRIPT_NAME']
    )
  )
end
endpoint() click to toggle source

Enforce trailing slash

# File lib/api_valve/forwarder.rb, line 103
def endpoint
  @endpoint ||= File.join(@options[:endpoint], '')
end
faraday() click to toggle source
# File lib/api_valve/forwarder.rb, line 92
def faraday
  @faraday ||= Faraday.new(
    url: endpoint,
    ssl: {verify: false}
  ) do |config|
    config.request :instrumentation
    config.adapter Faraday.default_adapter
  end
end
log_request(request) click to toggle source
# File lib/api_valve/forwarder.rb, line 71
def log_request(request)
  ApiValve.logger.debug do
    format(
      '-> %<method>s %<endpoint>s%<path>s',
      method:   request.method.upcase,
      endpoint: endpoint,
      path:     request.path
    )
  end
end
log_response(response, elapsed_time) click to toggle source
# File lib/api_valve/forwarder.rb, line 82
def log_response(response, elapsed_time)
  ApiValve.logger.debug do
    format(
      '<- %<status>s in %<ms>dms',
      status: response.status,
      ms:     elapsed_time * 1000
    )
  end
end
request_options() click to toggle source
# File lib/api_valve/forwarder.rb, line 50
def request_options
  (@options[:request] || {})
end
response_options() click to toggle source
# File lib/api_valve/forwarder.rb, line 54
def response_options
  (@options[:response] || {})
end
run_request(request) click to toggle source
# File lib/api_valve/forwarder.rb, line 58
def run_request(request)
  log_request request
  response, elapsed_time = benchmark do
    faraday.run_request(request.method, request.path, request.body, request.headers) do |req|
      req.params.update(request.url_params) if request.url_params
    end
  end
  log_response response, elapsed_time
  response
rescue Faraday::ConnectionFailed
  raise Error::ServiceUnavailable
end