jnunemaker / httparty

:tada: Makes http fun again!
MIT License
5.81k stars 964 forks source link

Extract request building method #786

Closed aliismayilov closed 1 year ago

aliismayilov commented 1 year ago

I'm writing a small extension for HTTParty to add AWS Signature V4 on HTTParty requests. This is achieved by adding computed headers to an existing request object based on its attributes like HTTP method, URL and body. Currently request object is not exposed, so, I end up building a request object and then signing it:

# current pseudo-code
class Client
  def self.foo(body)
    sign_v4(Net::HTTP::Post, "/foo", {body:}).perform
  end

  def self.sign_v4(http_method, path, options = {})
    # build request
    options = ModuleInheritableAttributes.hash_deep_dup(default_options).merge(options)
    HeadersProcessor.new(headers, options).call
    process_cookies(options)
    request = Request.new(http_method, path, options)

    # sign request
    signature = Aws::Sigv4::Signer.new.sign_request(http_method:, url:, body:)

    request.options[:headers] ||= {}
    request.options[:headers].merge!(signature.headers)

    request
  end
end

As you can see, I ended up copy/pasting the contents of perform_request. With the proposed extraction of build_request I can write a bit more concise code without having to dig into HTTParty internals:

# pseudo-code after this PR
class Client
  def self.foo(body)
    request = build_request(Net::HTTP::Post, "/foo", {body:})
    sign_v4(request).perform
  end

  def self.sign_v4(request)
    # sign request
    signature = Aws::Sigv4::Signer.new.sign_request(
      http_method: request.http_method,
      url: request.url,
      body: request.options[:body]
    )

    request.options[:headers] ||= {}
    request.options[:headers].merge!(signature.headers)

    request
  end
end

It's a minor refactor, but would make writing such extension much simpler and without worrying too much about HTTParty internals on how the request is built.