require 'rest-client' require 'json' module Afterbanks class << self attr_accessor :configuration def configuration @configuration ||= Configuration.new end def configure yield(configuration) end def api_call(method:, path:, params: {}) url = 'https://api.afterbanks.com' + path # Timeout is set to 5min: some banks take a lot to respond (e.g. ING Direct) request_params = { method: method, url: url, timeout: 60*5 } if method == :post request_params.merge!(payload: params) else request_params.merge!(headers: { params: params }) end response = begin RestClient::Request.execute(request_params) rescue RestClient::BadRequest, RestClient::ExpectationFailed => bad_request bad_request.response end debug_id = response.headers[:debug_id] log_request( method: method, url: url, params: params, debug_id: debug_id ) response_body = JSON.parse(response.body) treat_errors_if_any( response_body: response_body, debug_id: debug_id ) [response_body, debug_id] end def log_request(method:, url:, params: {}, debug_id: nil) logger = Afterbanks.configuration.logger return if logger.nil? now = Time.now safe_params = {} params.each do |key, value| safe_value = if %w{servicekey user pass pass2}.include?(key.to_s) "<masked>" else value end safe_value = safe_value.to_s if safe_value.is_a?(Symbol) safe_params[key] = safe_value end logger.info( message: 'Afterbanks request', method: method.upcase.to_s, url: url, time: now.to_s, timestamp: now.to_i, debug_id: debug_id || 'none', params: safe_params ) end private def treat_errors_if_any(response_body:, debug_id:) return unless response_body.is_a?(Hash) code = response_body['code'] message = response_body['message'] additional_info = response_body['additional_info'] error_info = { message: message, debug_id: debug_id } case code when 1 raise GenericError.new(error_info) when 2 raise ServiceUnavailableTemporarilyError.new(error_info) when 3 raise ConnectionDataError.new(error_info) when 4 raise AccountIdDoesNotExistError.new(error_info) when 5 raise CutConnectionError.new(error_info) when 6 raise HumanActionNeededError.new(error_info) when 50 unless additional_info raise MissingParameterError.new(error_info) end error_info.merge!(additional_info: additional_info) if additional_info.is_a?(Hash) && additional_info['session_id'] raise TwoStepAuthenticationError.new(error_info) else raise AccountIdNeededError.new(error_info) end end nil end end end