Module: PoliPage::Internal::HTTP Private
- Defined in:
- lib/poli_page/internal/http.rb
Overview
This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.
Pure transport helpers — no I/O, no socket access. Mirrors ‘sdk-node/src/internal/http.ts` (sdk-ruby-plan.md §13 Phase 1).
Constant Summary collapse
- STATUS_MAP =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
{ 400 => PoliPage::ValidationError, 401 => PoliPage::AuthenticationError, 403 => PoliPage::PermissionDeniedError, 404 => PoliPage::NotFoundError, 410 => PoliPage::GoneError, 429 => PoliPage::RateLimitError }.freeze
Class Method Summary collapse
- .build_headers(method:, api_key:, idempotency_key:, user_agent:) ⇒ Hash{String=>String} private
-
.build_url(base, path) ⇒ String
private
The joined URL with exactly one slash between the two.
-
.classify(status:, code:, message:, request_id:) ⇒ PoliPage::Error
private
Map an API response (status + parsed code/message) to the most specific ‘PoliPage::Error` subclass (sdk-ruby-plan.md §7).
-
.compute_backoff(attempt:, base_delay:, retry_after: nil) ⇒ Object
private
Compute the delay (in seconds) before the next retry attempt.
-
.parse_error_body(body, status) ⇒ Array(String, String)
private
Parse a non-2xx response body into a ‘[code, message]` pair.
- .parse_json_or_nil(body) ⇒ Object private
-
.parse_retry_after(header_value) ⇒ Object
private
Parse the ‘Retry-After` response header.
Class Method Details
.build_headers(method:, api_key:, idempotency_key:, user_agent:) ⇒ Hash{String=>String}
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/poli_page/internal/http.rb', line 29 def build_headers(method:, api_key:, idempotency_key:, user_agent:) headers = { Constants::HEADER_ACCEPT => "application/json", Constants::HEADER_AUTHORIZATION => "Bearer #{api_key}", Constants::HEADER_USER_AGENT => user_agent } if method == :post headers[Constants::HEADER_CONTENT_TYPE] = "application/json" headers[Constants::HEADER_IDEMPOTENCY_KEY] = idempotency_key if idempotency_key end headers end |
.build_url(base, path) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the joined URL with exactly one slash between the two.
20 21 22 |
# File 'lib/poli_page/internal/http.rb', line 20 def build_url(base, path) "#{base.chomp("/")}/#{path.sub(%r{\A/}, "")}" end |
.classify(status:, code:, message:, request_id:) ⇒ PoliPage::Error
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Map an API response (status + parsed code/message) to the most specific ‘PoliPage::Error` subclass (sdk-ruby-plan.md §7).
108 109 110 111 |
# File 'lib/poli_page/internal/http.rb', line 108 def classify(status:, code:, message:, request_id:) klass = STATUS_MAP.fetch(status, PoliPage::APIError) klass.new(, code: code, status: status, request_id: request_id) end |
.compute_backoff(attempt:, base_delay:, retry_after: nil) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Compute the delay (in seconds) before the next retry attempt. When ‘retry_after` is non-nil, it is returned as-is (server-explicit, no jitter). Otherwise: `base_delay * 2**(attempt-1) * (0.5 + rand)`. `attempt` is 1-based: 1 means the first retry.
93 94 95 96 97 98 |
# File 'lib/poli_page/internal/http.rb', line 93 def compute_backoff(attempt:, base_delay:, retry_after: nil) return retry_after unless retry_after.nil? exp = base_delay * (2**(attempt - 1)) exp * (0.5 + rand) end |
.parse_error_body(body, status) ⇒ Array(String, String)
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Parse a non-2xx response body into a ‘[code, message]` pair. Falls back to `INTERNAL_ERROR` when the body is not parseable JSON. The fallback chain (`code → message → error → ’unknown_error’‘) is ported verbatim from Node `parseErrorBody` (sdk-ruby-plan.md §7.3).
50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/poli_page/internal/http.rb', line 50 def parse_error_body(body, status) parsed = parse_json_or_nil(body) unless parsed.is_a?(Hash) return ["INTERNAL_ERROR", "HTTP #{status}: response body was not valid JSON"] end # RFC 7807: prefer `detail` (specific reason) over `title` (generic name) # over the legacy `message` field; fall back to a canned status string. # Code is verbatim from the API — never inferred from message. code = parsed.values_at("code", "error").compact.first || "unknown_error" = parsed.values_at("detail", "title", "message").compact.first || "HTTP #{status}" [code, ] end |
.parse_json_or_nil(body) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
65 66 67 68 69 |
# File 'lib/poli_page/internal/http.rb', line 65 def parse_json_or_nil(body) JSON.parse(body) rescue JSON::ParserError, TypeError nil end |
.parse_retry_after(header_value) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Parse the ‘Retry-After` response header. Accepts an integer number of seconds or an HTTP-date. Returns the delay in seconds (Ruby’s ‘Kernel#sleep` and `Net::HTTP#*_timeout` units), capped at `RETRY_AFTER_CAP` (30 s). Returns `nil` when the header is missing or unparseable. Mirrors Node `parseRetryAfter` modulo unit (ms → s).
76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/poli_page/internal/http.rb', line 76 def parse_retry_after(header_value) return nil if header_value.nil? || header_value.empty? return header_value.to_i.clamp(0, Constants::RETRY_AFTER_CAP) if /\A\d+\z/.match?(header_value) begin target = Time.httpdate(header_value) rescue ArgumentError return nil end (target - Time.now).floor.clamp(0, Constants::RETRY_AFTER_CAP) end |