lib/spyke/http.rb
require 'spyke/config'
require 'spyke/path'
require 'spyke/result'
require 'spyke/normalized_validation_error'
module Spyke
module Http
extend ActiveSupport::Concern
METHODS = %i{ get post put patch delete }
included do
class_attribute :connection, instance_accessor: false
end
module ClassMethods
METHODS.each do |method|
define_method(method) do
new_instance_or_collection_from_result scoped_request(method)
end
end
def request(method, path, params = {})
ActiveSupport::Notifications.instrument('request.spyke', method: method) do |payload|
response = send_request(method, path, params)
payload[:url], payload[:status] = response.env.url, response.status
Result.new_from_response(response)
end
end
def new_instance_from_result(result)
new_or_return result.data if result.data
end
def new_collection_from_result(result)
Collection.new Array(result.data).map { |record| new_or_return(record) }, result.metadata
end
def uri(uri_template = nil)
@uri ||= uri_template || default_uri
end
private
def send_request(method, path, params)
connection.send(method) do |request|
if method == :get
path, params = merge_query_params(path, params)
request.url path, params
else
request.url path.to_s
request.body = params
end
end
rescue Faraday::ConnectionFailed, Faraday::TimeoutError
raise ConnectionError
end
def merge_query_params(path, params)
parsed_uri = Addressable::URI.parse(path.to_s)
path = parsed_uri.path
params = params.merge(parsed_uri.query_values || {})
[path, params]
end
def scoped_request(method)
uri = new.uri
params = current_scope.params.except(*uri.variables)
request(method, uri, params)
end
def new_instance_or_collection_from_result(result)
if result.data.is_a?(Array)
new_collection_from_result(result)
else
new_instance_from_result(result)
end
end
def new_or_return(attributes_or_object)
if attributes_or_object.is_a?(Spyke::Base)
attributes_or_object
else
new attributes_or_object
end
end
def default_uri
"#{model_name.element.pluralize}(/:#{primary_key})"
end
end
METHODS.each do |method|
define_method(method) do |action = nil, params = {}|
params = action if action.is_a?(Hash)
path = resolve_path_from_action(action)
result = self.class.request(method, path, params)
add_errors_to_model(result.errors)
self.attributes = result.data
end
end
def uri
Path.new(@uri_template, attributes) if @uri_template
end
private
def add_errors_to_model(errors_hash)
errors_hash.each do |field, field_errors|
field_errors.each do |error_attributes|
error = NormalizedValidationError.new(error_attributes)
if ActiveSupport::VERSION::MAJOR < 5
errors.add(field.to_sym, error.message, error.options)
else
errors.add(field.to_sym, error.message, **error.options)
end
end
end
end
def resolve_path_from_action(action)
case action
when Symbol then uri.join(action)
when String then Path.new(action, attributes)
else uri
end
end
end
end