Module: Booqable::HTTP
- Included in:
- Client
- Defined in:
- lib/booqable/http.rb
Overview
HTTP request methods for Client
Provides low-level HTTP methods for making requests to the Booqable API. Handles authentication, pagination, rate limiting, and response parsing. All methods support both query parameters and request bodies as appropriate.
Constant Summary collapse
- CONVENIENCE_HEADERS =
Headers that can be passed as top-level options for convenience
Set.new(i[accept content_type user_agent])
Instance Method Summary collapse
-
#agent ⇒ Sawyer::Agent
private
Get or create the Sawyer agent for API requests.
-
#api_endpoint ⇒ String
private
Get the full API endpoint URL.
-
#default_headers ⇒ Hash
private
Get default HTTP headers for requests.
-
#delete(url, options = {}) ⇒ Sawyer::Resource
Make a HTTP delete request.
-
#faraday ⇒ Faraday::Connection
private
Get or create the Faraday connection instance.
-
#faraday_builder ⇒ Faraday::RackBuilder
private
Get or create the Faraday middleware builder.
-
#faraday_options ⇒ Hash
private
Get Faraday connection options.
-
#get(url, options = {}) ⇒ Sawyer::Resource
Make a HTTP GET request.
-
#head(url, options = {}) ⇒ Sawyer::Resource
Make a HTTP head request.
-
#last_response ⇒ Sawyer::Response?
Response for the last HTTP request.
-
#last_response_body ⇒ Hash?
private
Get the decoded body of the last response.
-
#logger ⇒ Logger?
private
Get logger instance for debug output.
-
#normalized_path(path) ⇒ String
private
Normalize a path to ensure it is a valid URL path.
-
#paginate(url, options = {}) ⇒ Sawyer::Resource
Make a paginated request to the Booqable API.
-
#parse_options_with_convenience_headers(options) ⇒ Hash
private
Parse options and extract convenience headers.
-
#patch(url, options = {}) ⇒ Sawyer::Resource
Make a HTTP patch request.
-
#post(url, options = {}) ⇒ Sawyer::Resource
Make a HTTP post request.
-
#put(url, options = {}) ⇒ Sawyer::Resource
Make a HTTP put request.
-
#rate_limit ⇒ RateLimit
Get rate limit information from the last response.
-
#request(method, path, data, options = {}) ⇒ Sawyer::Resource
Make a HTTP request to the Booqable API.
-
#response_data_with_correct_encoding(response) ⇒ Object
private
Ensure response data has correct character encoding.
-
#sawyer_options ⇒ Hash
private
Get configuration options for Sawyer agent.
-
#sawyer_serializer ⇒ Booqable::JsonApiSerializer
private
Get the JSON:API serializer for Sawyer.
-
#total_present_in_stats? ⇒ Boolean
Checks if the total count is present in the last response stats.
Instance Method Details
#agent ⇒ Sawyer::Agent
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.
Get or create the Sawyer agent for API requests
Returns a memoized Sawyer::Agent configured with the API endpoint, serializer, and optional logging. Sawyer handles the low-level HTTP communication and response parsing.
252 253 254 255 256 257 |
# File 'lib/booqable/http.rb', line 252 def agent @agent ||= Sawyer::Agent.new(api_endpoint, ) do |agent| agent.response :logger, logger, bodies: true if logger end end |
#api_endpoint ⇒ 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.
Get the full API endpoint URL
Constructs the complete API endpoint URL from the configured company, domain, protocol, and API version. Validates that the API version is supported and that a company is specified.
365 366 367 368 369 370 371 |
# File 'lib/booqable/http.rb', line 365 def api_endpoint @api_endpoint ||= begin raise UnsupportedAPIVersion unless %w[4 boomerang].include?(api_version.to_s) raise CompanyRequired if company_id.nil? || company_id.empty? Addressable::URI.join("#{api_protocol}://#{company_id}.#{api_domain}/", "api/", api_version.to_s).to_s end end |
#default_headers ⇒ Hash
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.
Get default HTTP headers for requests
Returns the standard headers that should be included with every API request, including content type, accept headers, and user agent.
191 192 193 194 195 196 197 |
# File 'lib/booqable/http.rb', line 191 def default_headers { accept: default_media_type, content_type: default_media_type, user_agent: user_agent } end |
#delete(url, options = {}) ⇒ Sawyer::Resource
Make a HTTP delete request
61 62 63 |
# File 'lib/booqable/http.rb', line 61 def delete(url, = {}) request :delete, url, end |
#faraday ⇒ Faraday::Connection
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.
Get or create the Faraday connection instance
Returns a memoized Faraday connection configured with the appropriate middleware stack, authentication, and connection options.
180 181 182 |
# File 'lib/booqable/http.rb', line 180 def faraday @faraday ||= Faraday.new() end |
#faraday_builder ⇒ Faraday::RackBuilder
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.
Get or create the Faraday middleware builder
Creates a middleware stack with authentication and optionally removes retry middleware based on configuration. The builder is memoized for performance.
234 235 236 237 238 239 240 241 242 |
# File 'lib/booqable/http.rb', line 234 def faraday_builder @faraday_builder ||= @middleware.dup.tap do |builder| inject_auth_middleware(builder) # Remove retry middleware if no_retries is enabled if no_retries builder.handlers.delete_if { |handler| handler.klass == Faraday::Retry::Middleware } end end end |
#faraday_options ⇒ Hash
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.
Get Faraday connection options
Builds the configuration hash for the Faraday connection including URL, middleware builder, proxy settings, and SSL verification options.
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
# File 'lib/booqable/http.rb', line 206 def opts = || { headers: default_headers } opts[:url] = api_endpoint opts[:builder] = faraday_builder opts[:proxy] = proxy if proxy if opts[:ssl].nil? opts[:ssl] = { verify_mode: @ssl_verify_mode } if @ssl_verify_mode else verify = [:ssl][:verify] opts[:ssl] = { verify: verify, verify_mode: verify == false ? 0 : @ssl_verify_mode } end opts end |
#get(url, options = {}) ⇒ Sawyer::Resource
Make a HTTP GET request
25 26 27 |
# File 'lib/booqable/http.rb', line 25 def get(url, = {}) request :get, url, end |
#head(url, options = {}) ⇒ Sawyer::Resource
Make a HTTP head request
70 71 72 |
# File 'lib/booqable/http.rb', line 70 def head(url, = {}) request :head, url, end |
#last_response ⇒ Sawyer::Response?
Response for the last HTTP request
124 125 126 |
# File 'lib/booqable/http.rb', line 124 def last_response @last_response end |
#last_response_body ⇒ Hash?
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.
Get the decoded body of the last response
Parses the raw response body from the last HTTP request using the JSON:API serializer. Returns nil if no response is available.
308 309 310 |
# File 'lib/booqable/http.rb', line 308 def last_response_body sawyer_serializer.decode(@last_response.body) if @last_response end |
#logger ⇒ Logger?
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.
Get logger instance for debug output
Creates a logger that outputs to STDOUT with DEBUG level when debug mode is enabled. Returns nil when debug is disabled.
266 267 268 269 270 |
# File 'lib/booqable/http.rb', line 266 def logger @logger ||= Logger.new(STDOUT).tap do |logger| logger.level = Logger::DEBUG end if debug? end |
#normalized_path(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.
Normalize a path to ensure it is a valid URL path
Removes leading slashes and normalizes the path to prevent directory traversal attacks and ensure consistent formatting.
116 117 118 119 |
# File 'lib/booqable/http.rb', line 116 def normalized_path(path) relative_path = path.to_s.sub(%r{^/}, "") # Remove leading slash Addressable::URI.parse(relative_path.to_s).normalize.to_s end |
#paginate(url, options = {}) ⇒ Sawyer::Resource
Make a paginated request to the Booqable API.
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/booqable/http.rb', line 137 def paginate(url, = {}) if @per_page || @auto_paginate [:page] ||= {} [:page][:size] ||= @per_page || (@auto_paginate ? 25 : nil) [:page][:number] ||= 1 [:stats] ||= { total: "count" } # otherwise we don't get the total count in the response end data = request(:get, url, )[:data] if @auto_paginate && total_present_in_stats? # While there are more results to fetch, and we have not hit the rate limit while total_count = last_response_body[:meta][:stats][:total][:count] > data.length && rate_limit.remaining > 0 [:page][:number] = [:page][:number] + 1 request(:get, url, .dup) data.concat(@last_response.data[:data]) if @last_response.data[:data].is_a?(Array) end end data end |
#parse_options_with_convenience_headers(options) ⇒ Hash
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 options and extract convenience headers
Processes request options to extract convenience headers (like accept, content_type, user_agent) from the top level and moves them to the headers hash for proper HTTP header handling.
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
# File 'lib/booqable/http.rb', line 321 def () headers = .delete(:headers) || {} CONVENIENCE_HEADERS.each do |h| if header = .delete(h) headers[h] = header end end query = .delete(:query) || {} opts = { query: } opts[:query].merge!(query) if query.is_a?(Hash) opts[:headers] = headers unless headers.empty? opts end |
#patch(url, options = {}) ⇒ Sawyer::Resource
Make a HTTP patch request
52 53 54 |
# File 'lib/booqable/http.rb', line 52 def patch(url, = {}) request :patch, url, end |
#post(url, options = {}) ⇒ Sawyer::Resource
Make a HTTP post request
34 35 36 |
# File 'lib/booqable/http.rb', line 34 def post(url, = {}) request :post, url, end |
#put(url, options = {}) ⇒ Sawyer::Resource
Make a HTTP put request
43 44 45 |
# File 'lib/booqable/http.rb', line 43 def put(url, = {}) request :put, url, end |
#rate_limit ⇒ RateLimit
Get rate limit information from the last response
Extracts rate limiting information from the HTTP headers of the most recent API response. This includes remaining requests, reset time, and limit information.
169 170 171 |
# File 'lib/booqable/http.rb', line 169 def rate_limit RateLimit.from_response(@last_response) end |
#request(method, path, data, options = {}) ⇒ Sawyer::Resource
Make a HTTP request to the Booqable API
Low-level request method that handles authentication, error handling, and response processing. All other HTTP methods delegate to this method.
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/booqable/http.rb', line 88 def request(method, path, data, = {}) if data.is_a?(Hash) && .empty? data[:headers] = default_headers.merge(data.delete(:headers) || {}) if accept = data.delete(:accept) data[:headers][:accept] = accept end = data.dup end = () if [ :get, :head ].include?(method) @last_response = response = agent.call(method, normalized_path(path), data, ) response_data_with_correct_encoding(response) rescue Booqable::Error => e @last_response = nil raise e end |
#response_data_with_correct_encoding(response) ⇒ 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.
Ensure response data has correct character encoding
Reads the charset from the Content-Type header and forces the correct encoding on string response data. Returns the response data unchanged if no charset is specified or data is not a string.
347 348 349 350 351 352 353 |
# File 'lib/booqable/http.rb', line 347 def response_data_with_correct_encoding(response) content_type = response.headers.fetch("content-type", "") return response.data unless content_type.include?("charset") && response.data.is_a?(String) reported_encoding = content_type.match(/charset=([^ ]+)/)[1] response.data.force_encoding(reported_encoding) end |
#sawyer_options ⇒ Hash
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.
Get configuration options for Sawyer agent
Returns the configuration hash for the Sawyer agent including the Faraday connection, link parser, and JSON:API serializer.
279 280 281 282 283 284 285 286 287 |
# File 'lib/booqable/http.rb', line 279 def { faraday: faraday, # simple link parser link_parser: Sawyer::LinkParsers::Simple.new, # use our own JSON API serializer serializer: sawyer_serializer } end |
#sawyer_serializer ⇒ Booqable::JsonApiSerializer
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.
Get the JSON:API serializer for Sawyer
Returns the configured JSON:API serializer that handles encoding and decoding of request/response bodies according to the JSON:API specification.
297 298 299 |
# File 'lib/booqable/http.rb', line 297 def sawyer_serializer Booqable::JsonApiSerializer.any_json end |
#total_present_in_stats? ⇒ Boolean
Checks if the total count is present in the last response stats.
376 377 378 379 380 381 |
# File 'lib/booqable/http.rb', line 376 def total_present_in_stats? last_response_body && last_response_body[:meta] && last_response_body[:meta][:stats] && last_response_body[:meta][:stats][:total] end |