Created
April 16, 2024 15:17
-
-
Save martinstreicher/334e24943a51495dbddd67901ed29b51 to your computer and use it in GitHub Desktop.
A sample base class for HTTP requests
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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