3

I'm using Faraday to create an SDK that will interact with an API, and I need to send two headers API_SIGNATURE and API_REQUEST_TIME, so that's what I've created:

class APIClient
  def initialize(api_key)
    @api_key = api_key
  end

  def get_users
    request.post('/users')
  end

  private

  def request
    Faraday.new(@@BASE_API_URL, headers: headers)
  end

  def headers
    timestamp = Time.now.to_i.to_s
    return {
      API_SIGNATURE: Digest::MD5.hexdigest(@api_key + timestamp),
      API_REQUEST_TIME: timestamp
    }
  end
end

And for some reason Faraday is changing API_SIGNATURE to Api-Signature and API_REQUEST_TIME to Api-Request-Time. Is it possible to prevent that from happening?

Thank you.

  • 1
    HTTP header fields are case-insensitive. It should not matter: https://stackoverflow.com/a/5259004/823617 Tell the API creators their API is out of spec. – Casper Oct 18 '19 at 15:59
  • Agreed. They are working on a new API though. –  Oct 18 '19 at 17:54

1 Answers1

1

You can change the keys to strings, but you'll find then that Net::HTTP changes the keys to: Api_signature and Api_request_time. See here for more info: https://github.com/lostisland/faraday/issues/747#issuecomment-439864181

One way you could maybe get around this, though it's a bit hacky, is to create a String class that doesn't lowercase itself like this:

class UpperCaseString < String
  def downcase
    self
  end
end

Then define your headers like so:

  def headers
    timestamp = Time.now.to_i.to_s
    return {
      UpperCaseString.new('API_SIGNATURE') => Digest::MD5.hexdigest(@api_key + timestamp),
      UpperCaseString.new('API_REQUEST_TIME') => timestamp
    }
  end

Possibly better is to use a different adapter like patron. Add it to your Gemfile then adjust the request to use it:

  def request
    Faraday.new(@@BASE_API_URL, headers: headers) do |faraday|
      faraday.adapter :patron
    end
  end

In this case you'd still need to make sure your headers are strings not symbols:

  def headers
    timestamp = Time.now.to_i.to_s
    {
      'API_SIGNATURE' => Digest::MD5.hexdigest(@api_key + timestamp),
      'API_REQUEST_TIME' => timestamp
    }
  end
rainkinz
  • 10,082
  • 5
  • 45
  • 73
  • 1
    As a note the `return` is not necessary, that value will be returned implicitly if omitted. – tadman Oct 18 '19 at 17:23
  • @rainkinz using patron adapter fails with `patron/session.rb:330:in `handle_request': Operation timed out after 1002 milliseconds with 0 out of 0 bytes received (Faraday::TimeoutError)`. Any ideas? –  Oct 18 '19 at 19:11
  • It sounds like your @@BASE_API_URL is not something you can get to. Have you tried pinging it or going to the URL using the browser? – rainkinz Oct 18 '19 at 19:34
  • I believe it's because the headers are not changing. I've just inspected them using `puts request.headers`. –  Oct 18 '19 at 21:11