svyatov/http_wrapper

View on GitHub
lib/http_wrapper/request.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

require 'uri/common'

class HTTPWrapper
  class Request
    KNOWN_PARAMS_KEYS = %i[headers query cookie auth body user_agent content_type multipart].freeze

    def initialize(url, method, params = {}) # rubocop:disable Metrics/AbcSize
      Util.validate_hash_keys params, KNOWN_PARAMS_KEYS

      self.uri = url

      @query   = params[:query] || {}
      @headers = normalize_headers params[:headers]
      @method  = http_method_class_for method
      @cookie  = params[:cookie]

      @body_data      = params[:body]
      @multipart_data = params[:multipart]
      @user_agent     = params[:user_agent]
      @content_type   = params[:content_type] || default_content_type_for(method)

      if params[:auth]
        @login    = params[:auth].fetch(:login)
        @password = params[:auth].fetch(:password)
      end

      initialize_headers
    end

    attr_reader :uri

    def uri=(url)
      url = "http://#{url}" unless %r{\Ahttps?://}.match?(url)
      @uri = URI.parse url
    end

    def create
      merge_uri_query
      create_method_specific_request
    end

    private

    def normalize_headers(headers)
      normal_headers = {}
      headers&.each do |header, value|
        normal_headers[normalize_header header] = value
      end
      normal_headers
    end

    def normalize_header(header)
      header = header.to_s.tr('_', '-') if header.is_a? Symbol
      header.downcase
    end

    def http_method_class_for(method)
      Net::HTTP.const_get method.to_s.capitalize
    end

    def default_content_type_for(method)
      case method
      when :post, :put then POST_CONTENT_TYPE
      else DEFAULT_CONTENT_TYPE
      end
    end

    def initialize_headers
      @headers[USER_AGENT_HEADER_NAME]   ||= @user_agent
      @headers[CONTENT_TYPE_HEADER_NAME] ||= @content_type
      @headers[COOKIE_HEADER_NAME]       ||= @cookie if @cookie
    end

    def merge_uri_query
      return if @query.empty?

      original_query = @uri.query ? Util.query_to_hash(@uri.query) : {}
      merged_query = original_query.merge @query
      @uri.query = Util.hash_to_query merged_query
    end

    def create_method_specific_request
      @request = @method.new @uri, @headers
      set_body
      set_basic_auth
      @request
    end

    def set_body
      return unless @request.request_body_permitted?

      if @multipart_data
        set_body_from_multipart_data
      else
        set_body_from_body_data
      end
    end

    def set_body_from_multipart_data
      convert_body_data_to_multipart_data if @body_data
      @request.set_form @multipart_data, MULTIPART_CONTENT_TYPE
    end

    def convert_body_data_to_multipart_data
      @body_data = Util.query_to_hash(@body_data) unless @body_data.is_a? Hash
      @body_data.each { |key, value| @multipart_data << [key.to_s, value.to_s] }
    end

    def set_body_from_body_data
      return unless @body_data

      @request.body = @body_data.is_a?(Hash) ? Util.hash_to_query(@body_data) : @body_data
    end

    def set_basic_auth
      return unless @login && @password

      @request.basic_auth @login, @password
    end
  end
end