module TophatterMerchant class BaseException < StandardError; end class BadContentTypeException < BaseException; end class UnauthorizedException < BaseException; end class BadRequestException < BaseException; end class NotFoundException < BaseException; end class ServerErrorException < BaseException; end class Resource def initialize(hash) hash.each do |key, value| if respond_to?("#{key}=") send("#{key}=", value) else TophatterMerchant.logger.warn "Invalid attribute #{key} specified for #{self.class.name}" end end end def to_hash instance_variables.map do |instance_variable| key = instance_variable.to_s.delete('@') value = instance_variable_get(instance_variable) if value.is_a?(Array) && value.all? { |element| element.respond_to?(:to_hash) } value = value.map(&:to_hash) elsif value.respond_to?(:to_hash) value = value.to_hash end value ? [key, value] : nil end.compact.to_h end class << self protected def get(url:, params: {}) execute request(method: :get, url: url, params: params) end def post(url:, params: {}) execute request(method: :post, url: url, params: params) end def execute(request) TophatterMerchant.logger.debug "#{request.method.upcase} #{request.url} #{request.payload.inspect}" response = request.execute raise BadContentTypeException.new, "The server didn't return JSON. You probably made a bad request." if response.headers[:content_type] == 'text/html; charset=utf-8' JSON.parse(response.body) rescue RestClient::Request::Unauthorized, RestClient::Forbidden => e TophatterMerchant.logger.debug "#{e.class.name}: #{e.response.code} -> raising UnauthorizedException" raise UnauthorizedException.new, parse_error(e, e.message) rescue RestClient::ResourceNotFound => e TophatterMerchant.logger.debug "#{e.class.name}: #{e.response.code} -> raising NotFoundException" raise NotFoundException.new, parse_error(e, 'The API path you requested does not exist.') rescue RestClient::BadRequest => e TophatterMerchant.logger.debug "#{e.class.name}: #{e.response.code} -> raising BadRequestException" raise BadRequestException.new, parse_error(e, e.message) rescue RestClient::InternalServerError => e TophatterMerchant.logger.debug "#{e.class.name}: #{e.response.code} -> raising ServerErrorException" raise ServerErrorException.new, parse_error(e, 'The server encountered an internal error. This is probably a bug, and you should contact support.') end def request(method:, url:, params:) RestClient::Request.new( method: method, url: url, payload: TophatterMerchant.access_token.empty? ? params : params.merge(access_token: TophatterMerchant.access_token), headers: { accept: :json, content_type: :json, user_agent: 'Merchant API [Ruby] (https://github.com/tophatter/merchant-api-ruby)' } ) end def path TophatterMerchant.api_path end private def parse_error(exception, fallback) error = begin JSON.parse(exception.response) rescue {} end error['message'] || fallback end end end end