Module: ClientApiBuilder::Router
- Included in:
- NestedRouter
- Defined in:
- lib/client_api_builder/router.rb
Defined Under Namespace
Modules: ClassMethods
Class Method Summary collapse
Instance Method Summary collapse
- #base_url ⇒ Object
- #build_body(body, options) ⇒ Object
- #build_connection_options(options) ⇒ Object
- #build_headers(options) ⇒ Object
- #build_query(query, options) ⇒ Object
- #build_uri(path, query, options) ⇒ Object
- #escape_path(path) ⇒ Object
- #expected_response_code!(response, expected_response_codes, _options) ⇒ Object
- #get_retry_request_max_retries(options) ⇒ Object
- #get_retry_request_sleep_time(_e, options) ⇒ Object
- #handle_response(response, options, &block) ⇒ Object
- #instrument_request ⇒ Object
- #log_request_exception(exception) ⇒ Object
- #parse_response(response, _options) ⇒ Object
- #request_log_message ⇒ Object
- #request_wrapper(options, &block) ⇒ Object
- #retry_request(options) ⇒ Object
-
#retry_request?(exception, _options) ⇒ Boolean
Determines whether to retry on a given exception.
- #root_router ⇒ Object
Class Method Details
.included(base) ⇒ Object
8 9 10 11 12 13 14 15 |
# File 'lib/client_api_builder/router.rb', line 8 def self.included(base) base.extend InheritanceHelper::Methods base.extend ClassMethods base.include ::ClientApiBuilder::Section base.include ::ClientApiBuilder::NetHTTP::Request base.include(::ClientApiBuilder::ActiveSupportNotifications) if defined?(ActiveSupport) base.send(:attr_reader, :response, :request_options, :total_request_time, :request_attempts) end |
Instance Method Details
#base_url ⇒ Object
437 438 439 |
# File 'lib/client_api_builder/router.rb', line 437 def base_url self.class.base_url end |
#build_body(body, options) ⇒ Object
490 491 492 493 494 495 496 497 |
# File 'lib/client_api_builder/router.rb', line 490 def build_body(body, ) body = [:body] if .key?(:body) return nil unless body return body if body.is_a?(String) self.class.build_body(self, body) end |
#build_connection_options(options) ⇒ Object
461 462 463 464 465 466 467 |
# File 'lib/client_api_builder/router.rb', line 461 def () if [:connection_options] self.class..merge([:connection_options]) else self.class. end end |
#build_headers(options) ⇒ Object
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 |
# File 'lib/client_api_builder/router.rb', line 441 def build_headers() headers = {} add_header_proc = proc do |name, value| headers[name] = if value.is_a?(Proc) root_router.instance_eval(&value) elsif value.is_a?(Symbol) root_router.send(value) else value end end self.class.default_headers.each(&add_header_proc) [:headers]&.each(&add_header_proc) headers end |
#build_query(query, options) ⇒ Object
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 |
# File 'lib/client_api_builder/router.rb', line 469 def build_query(query, ) query_params = {} add_query_param_proc = proc do |name, value| query_params[name] = if value.is_a?(Proc) root_router.instance_eval(&value) elsif value.is_a?(Symbol) root_router.send(value) else value end end self.class.default_query_params.each(&add_query_param_proc) query&.each(&add_query_param_proc) [:query]&.each(&add_query_param_proc) query_params.empty? ? nil : self.class.build_query(self, query_params) end |
#build_uri(path, query, options) ⇒ Object
499 500 501 502 503 504 505 506 507 508 509 |
# File 'lib/client_api_builder/router.rb', line 499 def build_uri(path, query, ) # Properly join base_url and path to handle missing/extra slashes base = base_url.to_s base = base.chomp('/') if base.end_with?('/') path = path.to_s path = "/#{path}" unless path.start_with?('/') uri = URI(base + path) uri.query = build_query(query, ) uri end |
#escape_path(path) ⇒ Object
552 553 554 |
# File 'lib/client_api_builder/router.rb', line 552 def escape_path(path) path end |
#expected_response_code!(response, expected_response_codes, _options) ⇒ Object
511 512 513 514 515 516 |
# File 'lib/client_api_builder/router.rb', line 511 def expected_response_code!(response, expected_response_codes, ) return if expected_response_codes.empty? && response.is_a?(Net::HTTPSuccess) return if expected_response_codes.include?(response.code) raise(::ClientApiBuilder::UnexpectedResponse.new("unexpected response code #{response.code}", response)) end |
#get_retry_request_max_retries(options) ⇒ Object
584 585 586 |
# File 'lib/client_api_builder/router.rb', line 584 def get_retry_request_max_retries() [:retries] || self.class.[:max_retries] || 1 end |
#get_retry_request_sleep_time(_e, options) ⇒ Object
580 581 582 |
# File 'lib/client_api_builder/router.rb', line 580 def get_retry_request_sleep_time(_e, ) [:sleep] || self.class.[:sleep] || 0.05 end |
#handle_response(response, options, &block) ⇒ Object
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 |
# File 'lib/client_api_builder/router.rb', line 530 def handle_response(response, , &block) data = case [:return] when :response response when :body response.body else parse_response(response, ) end if block instance_exec(data, &block) else data end end |
#instrument_request ⇒ Object
556 557 558 559 560 561 |
# File 'lib/client_api_builder/router.rb', line 556 def instrument_request start_time = Time.now yield ensure @total_request_time = Time.now - start_time end |
#log_request_exception(exception) ⇒ Object
607 608 609 |
# File 'lib/client_api_builder/router.rb', line 607 def log_request_exception(exception) ::ClientApiBuilder.logger&.error(exception) end |
#parse_response(response, _options) ⇒ Object
518 519 520 521 522 523 524 525 526 527 528 |
# File 'lib/client_api_builder/router.rb', line 518 def parse_response(response, ) body = response.body return nil if body.nil? || body.empty? JSON.parse(body) rescue JSON::ParserError => e raise ::ClientApiBuilder::UnexpectedResponse.new( "Invalid JSON in response: #{e.}", response ) end |
#request_log_message ⇒ Object
611 612 613 614 615 616 617 618 619 620 621 622 |
# File 'lib/client_api_builder/router.rb', line 611 def return '' unless method = [:method].to_s.upcase uri = [:uri] return "#{method} [no URI]" unless uri response_code = response ? response.code : 'UNKNOWN' duration = total_request_time ? (total_request_time * 1000).to_i : 0 "#{method} #{uri.scheme}://#{uri.host}#{uri.path}[#{response_code}] took #{duration}ms" end |
#request_wrapper(options, &block) ⇒ Object
588 589 590 591 592 |
# File 'lib/client_api_builder/router.rb', line 588 def request_wrapper(, &block) retry_request() do instrument_request(&block) end end |
#retry_request(options) ⇒ Object
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 |
# File 'lib/client_api_builder/router.rb', line 563 def retry_request() @request_attempts = 0 max_attempts = get_retry_request_max_retries() begin @request_attempts += 1 yield rescue StandardError => e # Use StandardError instead of Exception to allow SystemExit, Interrupt, etc. to propagate log_request_exception(e) raise(e) if @request_attempts >= max_attempts || !retry_request?(e, ) sleep_time = get_retry_request_sleep_time(e, ) sleep(sleep_time) if sleep_time&.positive? retry end end |
#retry_request?(exception, _options) ⇒ Boolean
Determines whether to retry on a given exception. Override this method to customize retry behavior. By default, only retries on network-related errors, not application errors.
597 598 599 600 601 602 603 604 605 |
# File 'lib/client_api_builder/router.rb', line 597 def retry_request?(exception, ) case exception when Net::OpenTimeout, Net::ReadTimeout, Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::ETIMEDOUT, SocketError, EOFError true else false end end |
#root_router ⇒ Object
548 549 550 |
# File 'lib/client_api_builder/router.rb', line 548 def root_router self end |