class FrederickAPI::V2::Helpers::Requestor

Requestor for v2 client to use built on top of JsonApiClient::Query::Requestor

Constants

GET_VIA_POST_PATHS

Paths that may have an unbounded query param length so we should always use a POST instead of a GET to get around AWS Cloudfront limitations

JSON_API_CLIENT_PASSTHROUGH_ERRORS

For backward compatibility, preserve these JSON API client errors instead of raising FrederickAPI::Errors::Error

Attributes

path[R]

Public Class Methods

new(klass, path = nil) click to toggle source
# File lib/frederick_api/v2/helpers/requestor.rb, line 28
def initialize(klass, path = nil)
  @klass = klass
  @path = path
end

Public Instance Methods

get(params = {}) click to toggle source
# File lib/frederick_api/v2/helpers/requestor.rb, line 42
def get(params = {})
  path = resource_path(params)

  params.delete(klass.primary_key)
  if get_via_post_path?(path)
    return request(:post, path, body: params.to_json, additional_headers: { 'X-Request-Method' => 'GET' })
  end

  request(:get, path, params: params)
end
linked(path) click to toggle source
Calls superclass method
# File lib/frederick_api/v2/helpers/requestor.rb, line 53
def linked(path)
  uri = URI.parse(path)
  return super unless get_via_post_path?(uri.path)

  path_without_params = "#{uri.scheme}://#{uri.host}#{uri.path}"
  params = uri.query ? CGI.parse(uri.query).each_with_object({}) { |(k, v), h| h[k] = v[0] } : {}
  request(:post, path_without_params, body: params.to_json, additional_headers: { 'X-Request-Method' => 'GET' })
end
request(type, path, params: nil, body: nil, additional_headers: {}) click to toggle source

Retry once on unhandled server errors

# File lib/frederick_api/v2/helpers/requestor.rb, line 63
def request(type, path, params: nil, body: nil, additional_headers: {})
  headers = klass.custom_headers.merge(additional_headers)
  make_request = proc do
    handle_background(handle_errors(make_request(type, path, params: params, body: body, headers: headers)))
  end

  begin
    make_request.call
  rescue JsonApiClient::Errors::ConnectionError, JsonApiClient::Errors::ServerError => ex
    raise ex if ex.is_a?(JsonApiClient::Errors::NotFound) || ex.is_a?(JsonApiClient::Errors::Conflict)
    make_request.call
  end
end
resource_path(parameters) click to toggle source
# File lib/frederick_api/v2/helpers/requestor.rb, line 33
def resource_path(parameters)
  base_path = path || klass.path(parameters)
  if (resource_id = parameters[klass.primary_key])
    File.join(base_path, encode_part(resource_id))
  else
    base_path
  end
end

Private Instance Methods

get_via_post_path?(path) click to toggle source
# File lib/frederick_api/v2/helpers/requestor.rb, line 102
def get_via_post_path?(path)
  GET_VIA_POST_PATHS.any? { |r| r.match(path) }
end
handle_background(response) click to toggle source
# File lib/frederick_api/v2/helpers/requestor.rb, line 78
def handle_background(response)
  return response unless
      (job = response&.first).is_a?(::FrederickAPI::V2::BackgroundJob) && job.status != 'complete'
  raise FrederickAPI::V2::Errors::BackgroundJobFailure, job if job.has_errors?
  sleep job.retry_after
  linked(job.links.attributes['self'])
end
handle_errors(result) click to toggle source
# File lib/frederick_api/v2/helpers/requestor.rb, line 86
def handle_errors(result)
  return result unless result.has_errors?
  error_klass = FrederickAPI::V2::Errors::ERROR_CODES[result.errors.first[:status]] ||
    FrederickAPI::V2::Errors::Error
  raise error_klass, result
end
handle_json_api_client_error(error) click to toggle source
# File lib/frederick_api/v2/helpers/requestor.rb, line 106
def handle_json_api_client_error(error)
  raise error if JSON_API_CLIENT_PASSTHROUGH_ERRORS.include?(error.class)

  klass.parser.parse(klass, error.env.response)
end
make_request(type, path, params:, body:, headers:) click to toggle source
# File lib/frederick_api/v2/helpers/requestor.rb, line 93
def make_request(type, path, params:, body:, headers:)
  faraday_response = connection.run(type, path, params: params, body: body, headers: headers)
  return klass.parser.parse(klass, faraday_response) unless faraday_response.status == 303

  linked(faraday_response.headers['location'])
rescue JsonApiClient::Errors::ClientError => e
  handle_json_api_client_error(e)
end