class Ecoportal::API::Common::Client

@note

- You can see the documentation of the `HTTP` module in [the repository](https://github.com/httprb/http)
  - it does `extend` the module `Chainable` ([chainable.rb](https://github.com/httprb/http/blob/master/lib/http/chainable.rb)),
  - where all the http requests are dev by using `HTTP::Client#request` ([client.rb](https://github.com/httprb/http/blob/master/lib/http/client.rb))
  - which calls `build_request` (new `HTTP::Request`) and `perform` (new `HTTP::Connection`)
  - to return `HTTP::Response` ([response.rb](https://github.com/httprb/http/blob/master/lib/http/response.rb))

@attr_reader logger [Logger] the logger.

Constants

DELAY_REQUEST_RETRY

Attributes

logger[RW]

Public Class Methods

new(api_key:, version: "v1", host: "live.ecoportal.com", logger: nil) click to toggle source

@note the `api_key` will be automatically added as parameter `X-ApiKey` in the header of the http requests. @param api_key [String] the key version to stablish the api connection. @param version [String] it is part of the base url and will determine the api version we query against. @param host [String] api server domain. @param logger [Logger] an object with `Logger` interface to generate logs. @return [Client] an object that holds the configuration of the api connection.

# File lib/ecoportal/api/common/client.rb, line 24
def initialize(api_key:, version: "v1", host: "live.ecoportal.com", logger: nil)
  @version  = version
  @api_key  = api_key
  @logger   = logger
  @host     = host
  if host.match(/^localhost|^127\.0\.0\.1/)
    @base_uri = "http://#{host}/api/"
  else
    @base_uri = "https://#{host}/api/"
  end
  log(:info) { "#{version} client initialized pointing at #{host}" }
  if @api_key.nil? || @api_key.match(/\A\W*\z/)
    log(:error) { "Api-key missing!" }
  end
  @response_logging_enabled = true
end

Public Instance Methods

base_request() click to toggle source

Creates a HTTP object adding the `X-ApiKey` or `X-ECOPORTAL-API-KEY` param to the header, depending on the API version. @note It configures HTTP so it only allows body data in json format. @return [HTTP] HTTP object.

# File lib/ecoportal/api/common/client.rb, line 129
def base_request
  @base_request ||= begin
    case @version
    when "v2"
      HTTP.headers("X-ECOPORTAL-API-KEY" => @api_key).accept(:json)
    else
      HTTP.headers("X-ApiKey" => @api_key).accept(:json)
    end
  end
end
delete(path) click to toggle source

Sends an http `DELETE` request against the api version using `path` to complete the base url. @param path [String] the tail that completes the url of the request. @return [Common::Reponse] the basic custom response object.

# File lib/ecoportal/api/common/client.rb, line 101
def delete(path)
  instrument("DELETE", path) do
    request do |http|
      http.delete(url_for(path))
    end
  end
end
get(path, params: {}) click to toggle source

Sends an http `GET` request against the api version using `path` to complete the base url, and adding the key_value pairs of `params` in the http header. @param path [String] the tail that completes the url of the request. @param params [Hash] the header paramters of the http request (not including the api key). @option params [String] :page the current page we are requesting with given the `:per_page` offset. @option params [String] :per_page the offset or the number of entries you get per request. @option params [String] :q some text to search. Omit this parameter to target all the entries. @return [Common::Reponse] the basic custom response object.

# File lib/ecoportal/api/common/client.rb, line 62
def get(path, params: {})
  instrument("GET", path, params) do
    request do |http|
      http.get(url_for(path), params: params)
    end
  end
end
log(level, &block) click to toggle source

Logger interface. @example:

log(:info) {"General information on what's going on"}
log(:warn) {"This is a warning that something is likely to have gone amiss"}
log(:error) {"Something went wrong"}
log(:fatal) {"An unrecoverable error has happend"}

@param level [Symbol] the level that the message should be logged. @yield [] generates the message. @yieldreturn [String] the generated message.

# File lib/ecoportal/api/common/client.rb, line 50
def log(level, &block)
  logger.send(level, &block) if logger
end
patch(path, data:) click to toggle source

Sends an http `PATCH` request against the api version using `path` to complete the base url, and the `data` as a body of the http request. @note it automatically adds the http header param `Content-Type` as `application/json` @param path [String] the tail that completes the url of the request. @param data [String] the body of the query in json format. @return [Common::Reponse] the basic custom response object.

# File lib/ecoportal/api/common/client.rb, line 90
def patch(path, data:)
  instrument("PATCH", path, data) do
    request do |http|
      http.patch(url_for(path), json: data)
    end
  end
end
post(path, data:) click to toggle source

Sends an http `POST` request against the api version using `path` to complete the base url, and the `data` as a body of the http request. @note it automatically adds the http header param `Content-Type` as `application/json` @param path [String] the tail that completes the url of the request. @param data [String] the body of the query in json format. @return [Common::Reponse] the basic custom response object.

# File lib/ecoportal/api/common/client.rb, line 76
def post(path, data:)
  instrument("POST", path, data) do
    request do |http|
      http.post(url_for(path), json: data)
    end
  end
end
request() { |base_request| ... } click to toggle source

Allows to launch a different operation via `block`, providing the basic HTTP connection to the block. @yield [http] launch specific http request. @yieldparam http [HTTP] the http connection. @yieldreturn [Common::Response] the basic custom response object. @return [Common::Reponse] the basic custom response object.

# File lib/ecoportal/api/common/client.rb, line 115
def request
  wrap_response yield(base_request)
end
url_for(path) click to toggle source

Full URl builder of the request @param path [String] the tail that completes the url of the request. @return [String] the final url.

# File lib/ecoportal/api/common/client.rb, line 143
def url_for(path)
  @base_uri+@version+path
end
without_response_logging() { |self| ... } click to toggle source
# File lib/ecoportal/api/common/client.rb, line 147
def without_response_logging(&block)
  begin
    @response_logging_enabled = false
    yield self
  ensure
    @response_logging_enabled = true
  end
end
wrap_response(response) click to toggle source

Wrap with basic custom object of the gem for responses. @param response [HTTP::Response] @return [Common::Reponse] the basic custom response object.

# File lib/ecoportal/api/common/client.rb, line 122
def wrap_response(response)
  Ecoportal::API::Common::Response.new(response)
end

Private Instance Methods

instrument(method, path, data = nil, &block) click to toggle source
# File lib/ecoportal/api/common/client.rb, line 158
def instrument(method, path, data = nil, &block)
  raise "Expected block" unless block
  start_time = Time.now.to_f
  log(:info)  { "#{method} #{url_for(path)}" }
  log(:debug) { "Data: #{JSON.pretty_generate(data)}" }

  with_retry(&block).tap do |result|
    end_time = Time.now.to_f
    log(result.success?? :info : :warn) do
      "Took %.2fs, Status #{result.status}" % (end_time - start_time)
    end
    log(result.success?? :debug : :warn) do
      "Response: #{JSON.pretty_generate(result.body)}"
    end if @response_logging_enabled
  end
end
with_retry(attempts = 3, delay = DELAY_REQUEST_RETRY) { || ... } click to toggle source

Helper to ensure unexpected server errors do not bring client scripts immediately down

# File lib/ecoportal/api/common/client.rb, line 176
def with_retry(attempts = 3, delay = DELAY_REQUEST_RETRY)
  response = nil
  attempts.times do |i|
    response = yield
    return response unless unexpected_server_error?(response.status)
    log_unexpected_server_error(response)
    sleep(delay) if i < attempts
  end
  response
end