require 'httparty' require 'alula/monkey_patches' module Alula class Client include HTTParty class << self DEFAULT_CUSTOM_OPTIONS = { omitRelationships: true }.freeze def config @_config ||= Alula::ClientConfiguration.new end def configure yield config if block_given? end def request(http_method, resource_path, filters = {}, opts = {}) validate_request!(http_method, resource_path) unless resource_path.match(%r{^/public/v1}) request_opts = build_options(http_method, resource_path, filters, opts) api_url = video_request?(resource_path) ? config.video_api_url : config.api_url request_resource_path = video_request?(resource_path) ? resource_path.gsub(%r{^/video}, '') : resource_path # TODO: Handle network failures response = make_request(http_method, api_url + request_resource_path, request_opts) begin resp = AlulaResponse.from_httparty_response(response) rescue JSON::ParserError # TODO: Should be able to send better info up with this raise 'Unable to decode JSON' end resp end private def validate_request!(http_method, resource_path) config.ensure_api_key_set config.ensure_api_url_set if video_request?(resource_path) config.ensure_video_api_url_set config.ensure_video_api_key_set config.ensure_customer_id_set end ensure_method_allowable(http_method) config.ensure_role_set if %i[patch post put].include? http_method end def make_request(http_method, full_url, request_opts) send(http_method, full_url, request_opts) end def ensure_method_allowable(http_method) return if %i[get post put patch delete].include?(http_method) raise "Unable to send a request with #{http_method} http method" end def video_request?(resource_path) resource_path.match(%r{^/video}) end def build_options(http_method, resource_path, filters = {}, opts = {}) api_key = Alula::Client.config.impersonator_api_key || Alula::Client.config.api_key request_opts = { headers: { 'Authorization': "Bearer #{api_key}", 'User-Agent': "#{Alula::Client.config.user_agent || 'No Agent Set'}/alula-ruby v#{Alula::VERSION}" } }.merge(opts) handle_video_request(request_opts) if video_request?(resource_path) # Add token for all video requests request_opts[:headers]['Content-Type'] = 'application/json' unless opts[:multipart] case http_method when :patch, :post request_opts[:body] = opts[:multipart] ? filters : JSON.generate(filters) when :get request_opts = request_opts.merge build_rest_options(filters) if resource_path.match(%r{^/(rest|rpc)}) when :delete # Nothing special end if Alula::Client.config.debug request_opts[:debug_output] = Alula.logger logger Alula.logger, :info end request_opts end def build_rest_options(filters) request_opts = {} custom_options = filters.delete(:customOptions) pagination = filters.delete(:page) relationships = filters.delete(:include) sort = filters.delete(:sort) request_opts[:query] = { filter: filters } request_opts[:query][:customOptions] = Util.deep_merge(DEFAULT_CUSTOM_OPTIONS, custom_options) request_opts[:query][:page] = pagination if pagination request_opts[:query][:include] = relationships if relationships request_opts[:query][:sort] = sort if sort request_opts end def build_rpc_options(filters) filters end def handle_video_request(request_opts) if Alula::Client.config.internal set_token(request_opts, { internal: true }) else set_token(request_opts, { customerId: Alula::Client.config.customer_id }) end end def set_token(request_opts, payload) jwt = TokenExchange.fetch_video_token(payload) request_opts[:headers]['token'] = jwt end end end end