lib/yext/api/utils/middleware/default_parameters.rb
# frozen_string_literal: true
module Yext
module Api
module Utils
module Middleware
# Faraday Middleware for adding Configuration default values to API calls as needed.
#
# Most options can be set via scopes and the soped values will be kept if they are used.
# i.e. the existing query string values will be kept if they exist.
#
# Because Spyke puts `where` options into the body OR the query depending on the type of
# request being made, we have to move the Yext query options out of the body into the query
# if there is a body.
#
# The following configuration options are defaulted:
# validation_level: Added to query parameters if not already there and is not nil
# api_key: Added to query parameters if not already there
# api_version: Added to qeury parameters if not already there
# account_id: Inserted into the path if the path includes the Account default URI and no
# account_id was specified.
#
# The following values will be moved out of the body into the query string if they are found:
# account_id * Not used if in body. If set it will already be in the path.
# v
# api_key
# validation
# yext_username
# yext_user_id
class DefaultParameters < Faraday::Response::Middleware
extend Memoist
attr_reader :configuration,
:url,
:params,
:body_json,
:request_env
def call(call_env)
get_attribute_values(call_env)
body_json.delete(:account_id)
add_username_headers
add_default_query_params
save_query_params
save_body
@app.call(request_env)
end
private
def get_attribute_values(call_env)
@request_env = call_env
@configuration = Yext::Api.configuration
@url = request_env[:url]
@params = Rack::Utils.parse_nested_query(url.query).with_indifferent_access
@body_json = parse_body
end
def parse_body
if request_env.body.present?
JSON.parse(request_env.body, symbolize_names: true)
else
{}
end
end
def add_default_query_params
params.reverse_merge!(api_key: api_key, v: version)
params[:validation] ||= validation if validation.present?
end
def validation
return body_json.delete(:validation) if body_json.key?(:validation)
configuration.validation_level if configuration.validation_level.present?
end
def version
body_json.delete(:v) || configuration.api_version || "20161012"
end
def api_key
body_json.delete(:api_key) || configuration.api_key
end
def save_query_params
url.query = params.to_query
end
def save_body
extract_rooted_body
return if request_env.body.blank?
body_json[:id] = body_json.delete(:create_id) if body_json.key?(:create_id)
request_env.body = body_json.to_json
end
def extract_rooted_body
return unless body_json.keys.length == 1
sub_json = body_json[body_json.keys.first]
@body_json = sub_json if sub_json.is_a?(Hash)
end
def add_username_headers
user_id, username = extract_header_values
return unless %w[put post patch delete].include?(request_env[:method].to_s)
request_headers = request_env[:request_headers]
request_headers["Yext-Username"] = username if username.present?
request_headers["Yext-User-Id"] = user_id if user_id.present?
end
def extract_header_values
username = extract_defaulted_value(:yext_username, configuration.yext_username)
user_id = extract_defaulted_value(:yext_user_id, configuration.yext_user_id)
[user_id, username]
end
def extract_defaulted_value(param_name, default_value)
params.delete(param_name) || body_json.delete(param_name) || default_value
end
memoize :validation,
:version,
:api_key
end
end
end
end
end