ignacio-chiazzo/ruby_whatsapp_sdk

View on GitHub
lib/whatsapp_sdk/api/client.rb

Summary

Maintainability
A
45 mins
Test Coverage
# typed: strict
# frozen_string_literal: true

require "faraday"
require "faraday/multipart"

module WhatsappSdk
  module Api
    class Client
      extend T::Sig

      API_VERSIONS = T.let(
        [
          'v19.0', 'v18.0', 'v17.0', 'v16.0', 'v15.0', 'v14.0', 'v13.0', 'v12.0',
          'v11.0', 'v10.0', 'v9.0', 'v8.0', 'v7.0', 'v6.0', 'v5.0', 'v4.0', 'v3.3',
          'v3.2', 'v3.1', 'v3.0', 'v2.12', 'v2.11', 'v2.10', 'v2.9', 'v2.8', 'v2.7',
          'v2.6', 'v2.5', 'v2.4', 'v2.3', 'v2.2', 'v2.1'
        ].freeze,
        T::Array[String]
      )

      sig do
        params(
          access_token: String,
          api_version: String,
          logger: T.nilable(T.any(Logger, T.class_of(Logger))),
          logger_options: Hash
        ).void
      end
      def initialize(
        access_token,
        api_version = ApiConfiguration::DEFAULT_API_VERSION,
        logger = nil,
        logger_options = {}
      )
        @access_token = access_token
        @logger = logger
        @logger_options = logger_options

        validate_api_version(api_version)
        @api_version = api_version
      end

      sig do
        params(
          endpoint: String,
          full_url: T.nilable(String),
          http_method: String,
          params: T::Hash[T.untyped, T.untyped],
          headers: T::Hash[T.untyped, T.untyped],
          multipart: T::Boolean
        ).returns(T.nilable(T::Hash[T.untyped, T.untyped]))
      end
      def send_request(endpoint: "", full_url: nil, http_method: "post", params: {}, headers: {}, multipart: false)
        url = full_url || "#{ApiConfiguration::API_URL}/#{@api_version}/"

        faraday_request = T.unsafe(faraday(url: url, multipart: multipart))

        response = faraday_request.public_send(http_method, endpoint, request_params(params, headers), headers)

        return nil if response.body == ""

        JSON.parse(response.body)
      end

      sig do
        params(url: String, content_type_header: String, file_path: T.nilable(String))
          .returns(Net::HTTPResponse)
      end
      def download_file(url:, content_type_header:, file_path: nil)
        uri = URI.parse(url)
        request = Net::HTTP::Get.new(uri)
        request["Authorization"] = "Bearer #{@access_token}"
        request.content_type = content_type_header
        req_options = { use_ssl: uri.scheme == "https" }

        response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
          http.request(request)
        end

        File.write(file_path, response.body, mode: 'wb') if response.code == "200" && file_path

        response
      end

      private

      sig do
        params(
          params: T::Hash[T.untyped, T.untyped],
          headers: T::Hash[T.untyped, T.untyped]
        ).returns(T.any(T::Hash[T.untyped, T.untyped], String))
      end
      def request_params(params, headers)
        return params.to_json if params.is_a?(Hash) && headers['Content-Type'] == 'application/json'

        params
      end

      sig { params(url: String, multipart: T::Boolean).returns(Faraday::Connection) }
      def faraday(url:, multipart: false)
        ::Faraday.new(url) do |client|
          client.request(:multipart) if multipart
          client.request(:url_encoded)
          client.adapter(::Faraday.default_adapter)
          client.headers['Authorization'] = "Bearer #{@access_token}" unless @access_token.nil?
          client.response(:logger, @logger, @logger_options) unless @logger.nil?
        end
      end

      sig { params(api_version: String).void }
      def validate_api_version(api_version)
        raise ArgumentError, "Invalid API version: #{api_version}" unless API_VERSIONS.include?(api_version)
      end
    end
  end
end