Skip to content

Instantly share code, notes, and snippets.

@martinstreicher
Created April 16, 2024 15:17
Show Gist options
  • Save martinstreicher/334e24943a51495dbddd67901ed29b51 to your computer and use it in GitHub Desktop.
Save martinstreicher/334e24943a51495dbddd67901ed29b51 to your computer and use it in GitHub Desktop.
A sample base class for HTTP requests
# frozen_string_literal: true
require "net/http"
module Client
RequestError = Class.new(StandardError)
class Request
DEFAULT_HOSTNAME = "localhost"
DEFAULT_PORT = 80
DEFAULT_PROTOCOL = "https"
ALL_NET_HTTP_ERRORS = [
Errno::EINVAL,
Errno::ECONNRESET,
EOFError,
Net::HTTPBadResponse,
Net::HTTPHeaderSyntaxError,
Net::ProtocolError,
Timeout::Error
].freeze
include ActiveSupport::Concern
include Memery
def initialize(settings: nil)
@settings = settings || {}
end
def basic_authentication
configuration[:basic_auth] || {}
end
memoize def configuration(settings: @settings)
(
settings.presence ||
rails_configuration_for_service ||
{}
).deep_symbolize_keys
end
def body; end
def headers
configuration
.fetch(:headers, {})
.transform_keys { |key| key.to_s.split("_").map(&:capitalize).join("-") }
.transform_values(&:to_s)
end
def hostname
configuration.fetch :hostname, DEFAULT_HOSTNAME
end
def http_verb
configuration[:verb] || :get
end
def path
configuration[:path] || nil
end
def params
{}
end
def port
configuration.fetch :port, DEFAULT_PORT
end
def protocol
configuration.fetch :protocol, DEFAULT_PROTOCOL
end
memoize def response
http.request request
rescue *ALL_NET_HTTP_ERRORS => exception
raise RequestError, exception.message
end
memoize def response_body
JSON.parse response.body
end
memoize def response_code
response.code.to_i
end
memoize def uri
target =
configuration[:uri] ||
Addressable::URI.new.tap do |uri|
uri.hostname = hostname
uri.path = path
uri.port = port
uri.query_values = params
uri.scheme = protocol
end
URI.parse target
end
private
def debug?
configuration.fetch :debug, ENV["DEBUG_HTTP"].presence.to_boolean
end
def http
Net::HTTP.new(uri.host, uri.port).tap do |httpee|
httpee.set_debug_output($stdout) if debug?
httpee.use_ssl = uri.scheme == "https"
end
end
def rails_configuration_for_service
config =
begin
Rails.application.config_for(service_name)
rescue StandardError
nil
end
begin
config.presence || Rails.application.config_for(service_name.gsub(%r{/.*\z}, ""))
rescue StandardError
nil
end
end
def request
action = "Net::HTTP::#{http_verb.to_s.camelize}".constantize
action.new(uri.request_uri).tap do |req|
if body.present?
if respond_to?(:body_as_json)
req.body = body_as_json
else
req.set_form_data(body)
end
end
if basic_authentication.presence
req.basic_auth(basic_authentication[:username], basic_authentication[:password])
end
headers.each_pair do |header, value|
req[header] = value
end
end
end
memoize def service_name
self.class.name.underscore.gsub(/_(request|client)\z/i, "")
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment