require 'faraday' require 'faraday_middleware' module Adparlor module Facebook module MultipleRequestParamsEncoder def self.encode(query_hash) ids_path(query_hash.delete(:ids), query_hash.delete(:fields), query_hash.delete(:access_token)) end def self.ids_path(ids, fields, access_token) "ids=[#{ids.join(',')}]&fields=#{fields}&access_token=#{access_token}" end end module Api def base_uri Adparlor::Facebook.configuration.base_uri end def proxy_api_key Adparlor::Facebook.configuration.proxy_api_key end def conn Faraday.default_adapter = :httpclient @conn ||= Faraday.new do |faraday| faraday.request :multipart faraday.request :retry, max: 3, exceptions: [Exception] faraday.request :url_encoded faraday.response :json faraday.adapter Faraday.default_adapter faraday.headers['x-api-key'] = proxy_api_key unless proxy_api_key.nil? end end def conn_multi @conn_multi ||= Faraday.new( full_url('', {}), request: { params_encoder: Adparlor::Facebook::MultipleRequestParamsEncoder } ) do |faraday| faraday.request :retry, max: 3, exceptions: [Exception] faraday.response :json faraday.adapter Faraday.default_adapter faraday.headers['x-api-key'] = proxy_api_key unless proxy_api_key.nil? end end def get(path, options = {}) options[:fields] = self.class.fields(*options[:fields]) if options[:fields] && options[:fields].is_a?(Array) raise FbError.new('required parameter access_token missing', 500) unless options[:access_token] || path.include?('access_token') if path.to_s.empty? && options.key?(:ids) conn_multi.get '', options else conn.get full_url(path, options), options end rescue Faraday::ParsingError # FB has returned some data that we can't parse into JSON raise FbError.new("Unable to make request.", 500) end def post(path, options = {}, method = 'CREATE') self.class.validate_post_fields(*instance_variables.map { |k| k.to_s.delete('@') }, method) if self.class.respond_to?(:validate_post_fields) raise FbError.new('required parameter access_token missing', 500) unless options[:access_token] || path.include?('access_token') body = instance_variables.each_with_object({}) { |var, hash| hash[var.to_s.sub(/@/, '').to_sym] = instance_variable_get(var) } content_type_header = options.delete(:content_type_header) content_type_header ||= body[:source].respond_to?(:content_type) || !@files.nil? ? 'multipart/form-data' : 'application/json' body.delete(:files) body[:bytes] = Base64.encode64(open(body.delete(:source).io, &:read)) if body.key?(:source) conn.post full_url(path, options) do |request| request.headers['Content-Type'] = content_type_header request.params = options request.body = content_type_header == 'multipart/form-data' ? (@files || {}).merge(body) : body.to_json end rescue Faraday::ParsingError # FB has returned some data that we can't parse into JSON raise FbError.new("Unable to make request.", 500) end def delete(path, options = {}) raise FbError.new('required parameter access_token missing', 500) unless options[:access_token] || path.include?('access_token') conn.delete full_url(path, options) do |request| request.headers['Content-Type'] = 'application/json' request.params = options request.body = instance_variables.each_with_object({}) { |var, hash| hash[var.to_s.sub(/@/, '').to_sym] = instance_variable_get(var) }.to_json end rescue Faraday::ParsingError # FB has returned some data that we can't parse into JSON raise FbError.new("Unable to make request.", 500) end private def api_version(options) "/#{options.delete(:api_version) || Adparlor::Facebook.configuration.api_version}/" end def full_url(path, options) if URI.parse(path).scheme path else URI.join(base_uri, api_version(options), path.gsub(%r{\A/}, '')) end end end end end