client-api-builder 0.2.9 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +32 -1
- data/client-api-builder.gemspec +3 -3
- data/examples/basic_auth_example_client.rb +2 -0
- data/examples/lorem_ipsum_client.rb +16 -0
- data/lib/client-api-builder.rb +6 -0
- data/lib/client_api_builder/active_support_log_subscriber.rb +29 -0
- data/lib/client_api_builder/active_support_notifications.rb +25 -0
- data/lib/client_api_builder/nested_router.rb +6 -3
- data/lib/client_api_builder/router.rb +78 -9
- data/lib/client_api_builder/section.rb +2 -2
- data/script/console +5 -0
- metadata +7 -4
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: c22eb6c8362909af90380e2513875c7a82c4bd67028e5a601694c1d604fc599d
         | 
| 4 | 
            +
              data.tar.gz: e6ad4f872b67a07563b88f3880bbd1f3375ed2d628a4c15cdedb0734fc9723a3
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 5bbe4fe12d3ea5ca240b445630360346a0a1628c340c9ce602efbacfb185ad23c7215233dcb84cb245ff5d3961b0695e8d177a15c39f87e9f6f6b4c0d030e60c
         | 
| 7 | 
            +
              data.tar.gz: 44c82d195b80ad34205af3fa256523fa0a3a1e7249bd857ac7cc0cece431d9d75906f26a5714914075e0b9291d84ad5649704add740c099d960ad2e60ad3e2ee
         | 
    
        data/README.md
    CHANGED
    
    | @@ -1,2 +1,33 @@ | |
| 1 1 | 
             
            # client-api-builder
         | 
| 2 | 
            -
             | 
| 2 | 
            +
             | 
| 3 | 
            +
            Utility for creating API clients through configuration
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Example:
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            ```
         | 
| 8 | 
            +
            class LoremIpsumClient
         | 
| 9 | 
            +
              include ClientApiBuilder::Router
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              # by default it converts the body data to JSON
         | 
| 12 | 
            +
              # to convert the body to query params (x=1&y=2) use the following
         | 
| 13 | 
            +
              # if using active support change this to :to_query
         | 
| 14 | 
            +
              body_builder :query_params
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              base_url 'https://www.lipsum.com'
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              header 'Content-Type', 'application/x-www-form-urlencoded'
         | 
| 19 | 
            +
              header 'Accept', 'application/json'
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              # this creates a method called create_lorem_ipsum with 2 named arguments amont and what
         | 
| 22 | 
            +
              route :create_lorem_ipsum, '/feed/json', body: {amount: :amount, what: :what, start: 'yes', generate: 'Generate Lorem Ipsum'}
         | 
| 23 | 
            +
            end
         | 
| 24 | 
            +
            ```
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            How to use:
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            ```
         | 
| 29 | 
            +
            client = LoremIpsumClient.new
         | 
| 30 | 
            +
            payload = client.create_lorem_ipsum(amount: 10, what: 'words')
         | 
| 31 | 
            +
            puts payload.dig('feed', 'lipsum')
         | 
| 32 | 
            +
            # outputs: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam at.
         | 
| 33 | 
            +
            ```
         | 
    
        data/client-api-builder.gemspec
    CHANGED
    
    | @@ -2,10 +2,10 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            Gem::Specification.new do |s|
         | 
| 4 4 | 
             
              s.name        = 'client-api-builder'
         | 
| 5 | 
            -
              s.version     = '0. | 
| 5 | 
            +
              s.version     = '0.4.0'
         | 
| 6 6 | 
             
              s.licenses    = ['MIT']
         | 
| 7 | 
            -
              s.summary     = ' | 
| 8 | 
            -
              s.description = ' | 
| 7 | 
            +
              s.summary     = 'Utility for creating API clients through configuration'
         | 
| 8 | 
            +
              s.description = 'Create API clients through configuration with complete transparency'
         | 
| 9 9 | 
             
              s.authors     = ['Doug Youch']
         | 
| 10 10 | 
             
              s.email       = 'dougyouch@gmail.com'
         | 
| 11 11 | 
             
              s.homepage    = 'https://github.com/dougyouch/client-api-builder'
         | 
| @@ -0,0 +1,16 @@ | |
| 1 | 
            +
            class LoremIpsumClient
         | 
| 2 | 
            +
              include ClientApiBuilder::Router
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              # by default it converts the body data to JSON
         | 
| 5 | 
            +
              # to convert the body to query params (x=1&y=2) use the following
         | 
| 6 | 
            +
              # if using active support change this to :to_query
         | 
| 7 | 
            +
              body_builder :query_params
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              base_url 'https://www.lipsum.com'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              header 'Content-Type', 'application/x-www-form-urlencoded'
         | 
| 12 | 
            +
              header 'Accept', 'application/json'
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              # this creates a method called create_lorem_ipsum with 2 named arguments amont and what
         | 
| 15 | 
            +
              route :create_lorem_ipsum, '/feed/json', body: {amount: :amount, what: :what, start: 'yes', generate: 'Generate Lorem Ipsum'}
         | 
| 16 | 
            +
            end
         | 
    
        data/lib/client-api-builder.rb
    CHANGED
    
    | @@ -11,6 +11,12 @@ module ClientApiBuilder | |
| 11 11 | 
             
                end
         | 
| 12 12 | 
             
              end
         | 
| 13 13 |  | 
| 14 | 
            +
              class << self
         | 
| 15 | 
            +
                attr_accessor :logger
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              autoload :ActiveSupportNotifications, 'client_api_builder/active_support_notifications'
         | 
| 19 | 
            +
              autoload :ActiveSupportLogSubscriber, 'client_api_builder/active_support_log_subscriber'
         | 
| 14 20 | 
             
              autoload :NestedRouter, 'client_api_builder/nested_router'
         | 
| 15 21 | 
             
              autoload :QueryParams, 'client_api_builder/query_params'
         | 
| 16 22 | 
             
              autoload :Router, 'client_api_builder/router'
         | 
| @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
            require 'active_support'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            # Purpose is to log all requests
         | 
| 5 | 
            +
            module ClientApiBuilder
         | 
| 6 | 
            +
              class ActiveSupportLogSubscriber
         | 
| 7 | 
            +
                attr_reader :logger
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def initialize(logger)
         | 
| 10 | 
            +
                  @logger = logger
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def subscribe!
         | 
| 14 | 
            +
                  ActiveSupport::Notifications.subscribe('client_api_builder.request') do |event|
         | 
| 15 | 
            +
                    logger.info(generate_log_message(event))
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def generate_log_message(event)
         | 
| 20 | 
            +
                  client = event.payload[:client]
         | 
| 21 | 
            +
                  method = client.request_options[:method].to_s.upcase
         | 
| 22 | 
            +
                  uri = client.request_options[:uri]
         | 
| 23 | 
            +
                  response = client.response
         | 
| 24 | 
            +
                  response_code = response ? response.code : 'UNKNOWN'
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  "#{method} #{uri.scheme}://#{uri.host}#{uri.path}[#{response_code}] took #{event.duration.to_i}ms"
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
            require 'active_support'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            # Purpose is to change the instrument_request to use ActiveSupport::Notifications.instrument
         | 
| 5 | 
            +
            module ClientApiBuilder
         | 
| 6 | 
            +
              module ActiveSupportNotifications
         | 
| 7 | 
            +
                def instrument_request
         | 
| 8 | 
            +
                  start_time = Time.now
         | 
| 9 | 
            +
                  error = nil
         | 
| 10 | 
            +
                  result = nil
         | 
| 11 | 
            +
                  ActiveSupport::Notifications.instrument('client_api_builder.request', client: self) do
         | 
| 12 | 
            +
                    begin
         | 
| 13 | 
            +
                      result = yield
         | 
| 14 | 
            +
                    rescue Exception => e
         | 
| 15 | 
            +
                      error = e
         | 
| 16 | 
            +
                    end
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  raise(error) if error
         | 
| 20 | 
            +
                  result
         | 
| 21 | 
            +
                ensure
         | 
| 22 | 
            +
                  @total_request_time = Time.now - start_time
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| @@ -8,10 +8,12 @@ module ClientApiBuilder | |
| 8 8 | 
             
              class NestedRouter
         | 
| 9 9 | 
             
                include ::ClientApiBuilder::Router
         | 
| 10 10 |  | 
| 11 | 
            -
                attr_reader :root_router
         | 
| 11 | 
            +
                attr_reader :root_router,
         | 
| 12 | 
            +
                            :nested_router_options
         | 
| 12 13 |  | 
| 13 | 
            -
                def initialize(root_router)
         | 
| 14 | 
            +
                def initialize(root_router, nested_router_options)
         | 
| 14 15 | 
             
                  @root_router = root_router
         | 
| 16 | 
            +
                  @nested_router_options = nested_router_options
         | 
| 15 17 | 
             
                end
         | 
| 16 18 |  | 
| 17 19 | 
             
                def self.get_instance_method(var)
         | 
| @@ -39,7 +41,7 @@ module ClientApiBuilder | |
| 39 41 | 
             
                end
         | 
| 40 42 |  | 
| 41 43 | 
             
                def build_headers(options)
         | 
| 42 | 
            -
                  headers = root_router.build_headers(options)
         | 
| 44 | 
            +
                  headers = nested_router_options[:ignore_headers] ? {} : root_router.build_headers(options)
         | 
| 43 45 |  | 
| 44 46 | 
             
                  add_header_proc = proc do |name, value|
         | 
| 45 47 | 
             
                    headers[name] =
         | 
| @@ -63,6 +65,7 @@ module ClientApiBuilder | |
| 63 65 |  | 
| 64 66 | 
             
                def build_query(query, options)
         | 
| 65 67 | 
             
                  return nil if query.nil? && root_router.class.default_query_params.empty? && self.class.default_query_params.empty?
         | 
| 68 | 
            +
                  return nil if nested_router_options[:ignore_query] && query.nil? && self.class.default_query_params.empty?
         | 
| 66 69 |  | 
| 67 70 | 
             
                  query_params = {}
         | 
| 68 71 |  | 
| @@ -1,5 +1,6 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 | 
             
            require 'inheritance-helper'
         | 
| 3 | 
            +
            require 'json'
         | 
| 3 4 |  | 
| 4 5 | 
             
            module ClientApiBuilder
         | 
| 5 6 | 
             
              module Router
         | 
| @@ -8,7 +9,8 @@ module ClientApiBuilder | |
| 8 9 | 
             
                  base.extend ClassMethods
         | 
| 9 10 | 
             
                  base.include ::ClientApiBuilder::Section
         | 
| 10 11 | 
             
                  base.include ::ClientApiBuilder::NetHTTP::Request
         | 
| 11 | 
            -
                  base. | 
| 12 | 
            +
                  base.include(::ClientApiBuilder::ActiveSupportNotifications) if defined?(ActiveSupport)
         | 
| 13 | 
            +
                  base.send(:attr_reader, :response, :request_options, :total_request_time, :request_attempts)
         | 
| 12 14 | 
             
                end
         | 
| 13 15 |  | 
| 14 16 | 
             
                module ClassMethods
         | 
| @@ -26,7 +28,9 @@ module ClientApiBuilder | |
| 26 28 | 
             
                      headers: {},
         | 
| 27 29 | 
             
                      query_builder: Hash.method_defined?(:to_query) ? :to_query : :query_params,
         | 
| 28 30 | 
             
                      query_params: {},
         | 
| 29 | 
            -
                      response_procs: {}
         | 
| 31 | 
            +
                      response_procs: {},
         | 
| 32 | 
            +
                      max_retries: 1,
         | 
| 33 | 
            +
                      sleep: 0.05
         | 
| 30 34 | 
             
                    }.freeze
         | 
| 31 35 | 
             
                  end
         | 
| 32 36 |  | 
| @@ -79,6 +83,14 @@ module ClientApiBuilder | |
| 79 83 | 
             
                    add_value_to_class_method(:default_options, connection_options: connection_options)
         | 
| 80 84 | 
             
                  end
         | 
| 81 85 |  | 
| 86 | 
            +
                  def configure_retries(max_retries, sleep_time_between_retries_in_seconds = 0.05)
         | 
| 87 | 
            +
                    add_value_to_class_method(
         | 
| 88 | 
            +
                      :default_options,
         | 
| 89 | 
            +
                      max_retries: max_retries,
         | 
| 90 | 
            +
                      sleep: sleep_time_between_retries_in_seconds
         | 
| 91 | 
            +
                    )
         | 
| 92 | 
            +
                  end
         | 
| 93 | 
            +
             | 
| 82 94 | 
             
                  # add a query param to all requests
         | 
| 83 95 | 
             
                  def query_param(name, value = nil, &block)
         | 
| 84 96 | 
             
                    query_params = default_options[:query_params].dup
         | 
| @@ -309,19 +321,21 @@ module ClientApiBuilder | |
| 309 321 | 
             
                    code += "\n"
         | 
| 310 322 |  | 
| 311 323 | 
             
                    code += "def #{method_name}(" + method_args.join(', ') + ")\n"
         | 
| 312 | 
            -
                    code += "   | 
| 313 | 
            -
                    code += " | 
| 314 | 
            -
                    code += " | 
| 315 | 
            -
                    code += " | 
| 324 | 
            +
                    code += "  request_wrapper(__options__) do\n"
         | 
| 325 | 
            +
                    code += "    block ||= self.class.get_response_proc(#{method_name.inspect})\n"
         | 
| 326 | 
            +
                    code += "    __expected_response_codes__ = #{expected_response_codes.inspect}\n"
         | 
| 327 | 
            +
                    code += "    #{method_name}_raw_response(" + method_args.map { |a| a =~ /:$/ ? "#{a} #{a.sub(':', '')}" : a }.join(', ') + ")\n"
         | 
| 328 | 
            +
                    code += "    expected_response_code!(@response, __expected_response_codes__, __options__)\n"
         | 
| 316 329 |  | 
| 317 330 | 
             
                    if options[:stream] || options[:return] == :response
         | 
| 318 | 
            -
                      code += " | 
| 331 | 
            +
                      code += "    @response\n"
         | 
| 319 332 | 
             
                    elsif options[:return] == :body
         | 
| 320 | 
            -
                      code += " | 
| 333 | 
            +
                      code += "    @response.body\n"
         | 
| 321 334 | 
             
                    else
         | 
| 322 | 
            -
                      code += " | 
| 335 | 
            +
                      code += "    handle_response(@response, __options__, &block)\n"
         | 
| 323 336 | 
             
                    end
         | 
| 324 337 |  | 
| 338 | 
            +
                    code += "  end\n"
         | 
| 325 339 | 
             
                    code += "end\n"
         | 
| 326 340 | 
             
                    code
         | 
| 327 341 | 
             
                  end
         | 
| @@ -439,5 +453,60 @@ module ClientApiBuilder | |
| 439 453 | 
             
                def escape_path(path)
         | 
| 440 454 | 
             
                  path
         | 
| 441 455 | 
             
                end
         | 
| 456 | 
            +
             | 
| 457 | 
            +
                def instrument_request
         | 
| 458 | 
            +
                  start_time = Time.now
         | 
| 459 | 
            +
                  yield
         | 
| 460 | 
            +
                ensure
         | 
| 461 | 
            +
                  @total_request_time = Time.now - start_time
         | 
| 462 | 
            +
                end
         | 
| 463 | 
            +
             | 
| 464 | 
            +
                def retry_request(options)
         | 
| 465 | 
            +
                  @request_attempts = 0
         | 
| 466 | 
            +
                  max_attempts = get_retry_request_max_retries(options)
         | 
| 467 | 
            +
                  begin
         | 
| 468 | 
            +
                    @request_attempts += 1
         | 
| 469 | 
            +
                    yield
         | 
| 470 | 
            +
                  rescue Exception => e
         | 
| 471 | 
            +
                    log_request_exception(e)
         | 
| 472 | 
            +
                    raise(e) if @request_attempts >= max_attempts || !retry_request?(e, options)
         | 
| 473 | 
            +
                    sleep_time = get_retry_request_sleep_time(e, options)
         | 
| 474 | 
            +
                    sleep(sleep_time) if sleep_time && sleep_time > 0
         | 
| 475 | 
            +
                    retry
         | 
| 476 | 
            +
                  end
         | 
| 477 | 
            +
                end
         | 
| 478 | 
            +
             | 
| 479 | 
            +
                def get_retry_request_sleep_time(e, options)
         | 
| 480 | 
            +
                  options[:sleep] || self.class.default_options[:sleep] || 0.05
         | 
| 481 | 
            +
                end
         | 
| 482 | 
            +
             | 
| 483 | 
            +
                def get_retry_request_max_retries(options)
         | 
| 484 | 
            +
                  options[:retries] || self.class.default_options[:max_retries] || 1
         | 
| 485 | 
            +
                end
         | 
| 486 | 
            +
             | 
| 487 | 
            +
                def request_wrapper(options)
         | 
| 488 | 
            +
                  retry_request(options) do
         | 
| 489 | 
            +
                    instrument_request do
         | 
| 490 | 
            +
                      yield
         | 
| 491 | 
            +
                    end
         | 
| 492 | 
            +
                  end
         | 
| 493 | 
            +
                end
         | 
| 494 | 
            +
             | 
| 495 | 
            +
                def retry_request?(exception, options)
         | 
| 496 | 
            +
                  true
         | 
| 497 | 
            +
                end
         | 
| 498 | 
            +
             | 
| 499 | 
            +
                def log_request_exception(exception)
         | 
| 500 | 
            +
                  ::ClientApiBuilder.logger && ::ClientApiBuilder.logger.error(exception)
         | 
| 501 | 
            +
                end
         | 
| 502 | 
            +
             | 
| 503 | 
            +
                def request_log_message
         | 
| 504 | 
            +
                  method = request_options[:method].to_s.upcase
         | 
| 505 | 
            +
                  uri = request_options[:uri]
         | 
| 506 | 
            +
                  response_code = response ? response.code : 'UNKNOWN'
         | 
| 507 | 
            +
             | 
| 508 | 
            +
                  duration = (total_request_time * 1000).to_i
         | 
| 509 | 
            +
                  "#{method} #{uri.scheme}://#{uri.host}#{uri.path}[#{response_code}] took #{duration}ms"
         | 
| 510 | 
            +
                end
         | 
| 442 511 | 
             
              end
         | 
| 443 512 | 
             
            end
         | 
| @@ -8,7 +8,7 @@ module ClientApiBuilder | |
| 8 8 | 
             
                end
         | 
| 9 9 |  | 
| 10 10 | 
             
                module ClassMethods
         | 
| 11 | 
            -
                  def section(name, &block)
         | 
| 11 | 
            +
                  def section(name, nested_router_options={}, &block)
         | 
| 12 12 | 
             
                    kls = InheritanceHelper::ClassBuilder::Utils.create_class(
         | 
| 13 13 | 
             
                      self,
         | 
| 14 14 | 
             
                      name,
         | 
| @@ -24,7 +24,7 @@ def self.#{name}_router | |
| 24 24 | 
             
            end
         | 
| 25 25 |  | 
| 26 26 | 
             
            def #{name}
         | 
| 27 | 
            -
              @#{name} ||= self.class.#{name}_router.new(self.root_router)
         | 
| 27 | 
            +
              @#{name} ||= self.class.#{name}_router.new(self.root_router, #{nested_router_options.inspect})
         | 
| 28 28 | 
             
            end
         | 
| 29 29 | 
             
            CODE
         | 
| 30 30 | 
             
                    self.class_eval code, __FILE__, __LINE__
         | 
    
        data/script/console
    CHANGED
    
    | @@ -6,5 +6,10 @@ $LOAD_PATH << File.expand_path('../examples', __dir__) | |
| 6 6 | 
             
            require 'client-api-builder'
         | 
| 7 7 | 
             
            autoload :BasicAuthExampleClient, 'basic_auth_example_client'
         | 
| 8 8 | 
             
            autoload :IMDBDatesetsClient, 'imdb_datasets_client'
         | 
| 9 | 
            +
            autoload :LoremIpsumClient, 'lorem_ipsum_client'
         | 
| 10 | 
            +
            require 'logger'
         | 
| 11 | 
            +
            LOG = Logger.new(STDOUT)
         | 
| 12 | 
            +
            ClientApiBuilder.logger = LOG
         | 
| 13 | 
            +
            ClientApiBuilder::ActiveSupportLogSubscriber.new(LOG).subscribe!
         | 
| 9 14 | 
             
            require 'irb'
         | 
| 10 15 | 
             
            IRB.start(__FILE__)
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: client-api-builder
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.4.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Doug Youch
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2022-08- | 
| 11 | 
            +
            date: 2022-08-26 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: inheritance-helper
         | 
| @@ -24,7 +24,7 @@ dependencies: | |
| 24 24 | 
             
                - - ">="
         | 
| 25 25 | 
             
                  - !ruby/object:Gem::Version
         | 
| 26 26 | 
             
                    version: 0.2.5
         | 
| 27 | 
            -
            description:  | 
| 27 | 
            +
            description: Create API clients through configuration with complete transparency
         | 
| 28 28 | 
             
            email: dougyouch@gmail.com
         | 
| 29 29 | 
             
            executables: []
         | 
| 30 30 | 
             
            extensions: []
         | 
| @@ -40,7 +40,10 @@ files: | |
| 40 40 | 
             
            - client-api-builder.gemspec
         | 
| 41 41 | 
             
            - examples/basic_auth_example_client.rb
         | 
| 42 42 | 
             
            - examples/imdb_datasets_client.rb
         | 
| 43 | 
            +
            - examples/lorem_ipsum_client.rb
         | 
| 43 44 | 
             
            - lib/client-api-builder.rb
         | 
| 45 | 
            +
            - lib/client_api_builder/active_support_log_subscriber.rb
         | 
| 46 | 
            +
            - lib/client_api_builder/active_support_notifications.rb
         | 
| 44 47 | 
             
            - lib/client_api_builder/nested_router.rb
         | 
| 45 48 | 
             
            - lib/client_api_builder/net_http_request.rb
         | 
| 46 49 | 
             
            - lib/client_api_builder/query_params.rb
         | 
| @@ -69,5 +72,5 @@ requirements: [] | |
| 69 72 | 
             
            rubygems_version: 3.3.3
         | 
| 70 73 | 
             
            signing_key:
         | 
| 71 74 | 
             
            specification_version: 4
         | 
| 72 | 
            -
            summary:  | 
| 75 | 
            +
            summary: Utility for creating API clients through configuration
         | 
| 73 76 | 
             
            test_files: []
         |