Class: Forem::APIRequestor

Inherits:
Object
  • Object
show all
Defined in:
lib/forem/api_requestor.rb

Overview

Executes authenticated HTTP requests against the Forem API.

APIRequestor is the single entry-point for all network I/O in the library. It builds requests (including authentication headers), delegates transport to a ConnectionManager, parses the response, maps HTTP error status codes to typed ForemError subclasses, and applies automatic retry logic for transient failures.

Each Client owns its own APIRequestor, built from the client's Configuration. There is no global default requestor — every call must originate from a specific client instance (or pass an explicit :requestor option to a class-level resource method).

Examples:

Constructing directly (uncommon — prefer Client.new)

config = Forem::Configuration.new
config.api_key = "my_key"
requestor = Forem::APIRequestor.new(config: config)
requestor.request(:get, "/api/articles")

Instance Method Summary collapse

Constructor Details

#initialize(config:) ⇒ APIRequestor

Create a new APIRequestor.

Parameters:

  • config (Configuration)

    the configuration to use for this requestor.



30
31
32
33
# File 'lib/forem/api_requestor.rb', line 30

def initialize(config:)
  @config = config
  @connection_manager = ConnectionManager.new
end

Instance Method Details

#request(method, path, params = {}, opts = {}) ⇒ ForemResponse

Execute an HTTP request against the Forem API.

Builds the request, attaches authentication headers, sends it, and returns a ForemResponse. On HTTP 4xx/5xx responses the method raises the appropriate ForemError subclass. Transient failures (Forem::APIConnectionError, RateLimitError, server 5xx) are automatically retried up to Configuration#max_network_retries times. Rate-limit retries honor integer Retry-After seconds; other retries use exponential back-off.

Examples:

Fetching articles with pagination

resp = requestor.request(:get, "/api/articles", { page: 2, per_page: 10 })
resp.http_status  #=> 200
resp.parsed_body  #=> [{ "id" => 1, ... }, ...]

Parameters:

  • method (Symbol)

    the HTTP verb — :get, :post, :put, or :delete.

  • path (String)

    the API path relative to Configuration#api_base (e.g. "/api/articles").

  • params (Hash) (defaults to: {})

    query parameters for GET requests, or the JSON request body for POST/PUT requests. Defaults to {}.

  • opts (Hash) (defaults to: {})

    per-request overrides.

Options Hash (opts):

  • :api_key (String)

    override the API key for this request.

  • :api_base (String)

    override the base URL for this request.

  • :requestor (APIRequestor)

    an alternative requestor to use (consumed by higher-level helpers before reaching this method).

Returns:

Raises:

See Also:



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/forem/api_requestor.rb', line 73

def request(method, path, params = {}, opts = {})
  api_key = opts.delete(:api_key) || @config.api_key
  api_base = opts.delete(:api_base) || @config.api_base
  extra_headers = opts.delete(:headers) || {}
  uri = URI("#{api_base}#{path}")

  retries_left = @config.max_network_retries
  begin
    response = execute_request(method, uri, params, api_key, extra_headers)
    handle_error_response(response) if response.http_status >= 400
    response
  rescue Forem::APIConnectionError
    if retries_left > 0
      retries_left -= 1
      sleep backoff_duration(@config.max_network_retries - retries_left)
      retry
    end
    raise
  rescue Forem::RateLimitError, Forem::APIError => e
    if retries_left > 0 && retryable_error?(e)
      retries_left -= 1
      retry_count = @config.max_network_retries - retries_left
      sleep retry_delay(e, retry_count)
      retry
    end
    raise
  end
end