Class: Mailkube::Config

Inherits:
Object
  • Object
show all
Defined in:
lib/mailkube/config.rb,
sig/mailkube/config.rbs

Overview

Resolved client configuration: the key, the origin, the timeout and the default headers.

This is the only place configuration is read, and the only place a URL is built. Keeping the origin guard here rather than in a resource protects every future link-following feature for free. Instances are frozen: a client that cannot be reconfigured after construction is a client that cannot develop a concurrency bug.

Constant Summary collapse

ENV_API_KEY =

Environment variable holding the API key.

Returns:

  • (String)
"MAILKUBE_API_KEY"
ENV_BASE_URL =

Environment variable overriding the API base URL.

Returns:

  • (String)
"MAILKUBE_BASE_URL"
DEFAULT_TIMEOUT =

Per-request timeout in seconds when the caller does not set one.

Returns:

  • (Integer)
30

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(api_key: nil, base_url: nil, timeout: DEFAULT_TIMEOUT) ⇒ Config

Resolve configuration from the arguments, then the environment, then the defaults.

Parameters:

  • api_key (String, nil) (defaults to: nil)

    the API key; falls back to MAILKUBE_API_KEY.

  • base_url (String, nil) (defaults to: nil)

    the API base URL; falls back to MAILKUBE_BASE_URL.

  • timeout (Integer, Float) (defaults to: DEFAULT_TIMEOUT)

    the per-request timeout in seconds.

  • api_key: (String, nil) (defaults to: nil)
  • base_url: (String, nil) (defaults to: nil)
  • timeout: (Numeric) (defaults to: DEFAULT_TIMEOUT)

Raises:



34
35
36
37
38
39
40
41
42
# File 'lib/mailkube/config.rb', line 34

def initialize(api_key: nil, base_url: nil, timeout: DEFAULT_TIMEOUT)
  key = api_key || ENV.fetch(ENV_API_KEY, nil)
  raise ConfigurationError, "no API key provided: pass api_key: or set #{ENV_API_KEY}" if key.nil? || key.empty?

  @api_key = key
  @base_url = base_url || ENV.fetch(ENV_BASE_URL, nil) || Mailkube::DEFAULT_BASE_URL
  @timeout = timeout
  freeze
end

Instance Attribute Details

#base_urlString (readonly)

Returns the resolved API base URL, always ending in a slash.

Returns:

  • (String)

    the resolved API base URL, always ending in a slash.



24
25
26
# File 'lib/mailkube/config.rb', line 24

def base_url
  @base_url
end

#timeoutInteger, Float (readonly)

Returns the per-request timeout in seconds.

Returns:

  • (Integer, Float)

    the per-request timeout in seconds.



26
27
28
# File 'lib/mailkube/config.rb', line 26

def timeout
  @timeout
end

Instance Method Details

#build_url(path, params = {}) ⇒ String

Join a relative path onto the base URL, attach the query, and refuse any absolute URL off the base URL's origin.

Every request carries the Authorization header, so following a link that names a foreign host would hand that host the API key.

The query is attached after the origin check and only when there is one, so an absolute page link the API issued keeps its own query untouched and an unfiltered listing produces no ? at all. URI.encode_www_form — not Serialization.escape_segment — is correct here: a space in a query value is +, and a space in a path segment is %20.

Parameters:

  • path (String)

    a relative path, or an absolute URL the API itself issued.

  • params (Hash{String => String}) (defaults to: {})

    query parameters, already rendered to strings by Serialization.query.

  • (String)
  • (Hash[String, String])

Returns:

  • (String)

    the absolute URL to request.

Raises:



76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/mailkube/config.rb', line 76

def build_url(path, params = {})
  base = URI.parse(@base_url)
  resolved = base.merge(path)
  unless resolved.scheme == base.scheme && resolved.host == base.host && resolved.port == base.port
    raise ConfigurationError, "refusing to follow #{resolved}: it is not on the configured API origin"
  end

  resolved.query = URI.encode_www_form(params) unless params.empty?
  resolved.to_s
rescue URI::InvalidURIError, URI::InvalidComponentError => e
  raise ConfigurationError, "invalid URL #{path.inspect}: #{e.message}"
end

#default_headersHash{String => String}

The auth and non-browser identification headers sent on every request.

The User-Agent is required: the API rejects a request without one. It reports Mailkube::VERSION, which the gemspec also reads, so it cannot drift from the released version.

Returns:

  • (Hash{String => String})

    the default headers.



51
52
53
54
55
56
57
58
# File 'lib/mailkube/config.rb', line 51

def default_headers
  {
    "Authorization" => "Bearer #{@api_key}",
    "User-Agent" => "mailkube-ruby/#{VERSION}",
    "Content-Type" => "application/json",
    "Accept" => "application/json"
  }
end