Class: Multilocale::Client
- Inherits:
-
Object
- Object
- Multilocale::Client
- Defined in:
- lib/multilocale/client.rb
Overview
HTTP client for the Multilocale REST API (https://api.multilocale.com).
client = Multilocale::Client.new(api_key: ENV["MULTILOCALE_API_KEY"])
client.projects.list
client.dictionary(project: "website", language: "es")
Authentication is Authorization: Basic base64(secret) — the API key
secret on its own, base64'd, with no key/secret pair and no colon. The
secret selects both the organization and the project, so there is no
tenant parameter to pass and no way for a key to reach another project.
Constant Summary collapse
- DEFAULT_API_URL =
"https://api.multilocale.com"- DEFAULT_OPEN_TIMEOUT =
5- DEFAULT_READ_TIMEOUT =
30- DEFAULT_MAX_RETRIES =
2- DEFAULT_RETRY_BACKOFF =
0.5- RETRIABLE_STATUSES =
429 and 5xx are the transient ones. 4xx is the caller's problem and retrying it only burns rate limit.
[429, 500, 502, 503, 504].freeze
- RETRIABLE_EXCEPTIONS =
[ Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EHOSTUNREACH, EOFError, IOError, Net::OpenTimeout, Net::ReadTimeout, SocketError ].freeze
Instance Attribute Summary collapse
-
#api_url ⇒ Object
readonly
Returns the value of attribute api_url.
-
#max_retries ⇒ Object
readonly
Returns the value of attribute max_retries.
-
#open_timeout ⇒ Object
readonly
Returns the value of attribute open_timeout.
-
#project ⇒ Object
readonly
Returns the value of attribute project.
-
#read_timeout ⇒ Object
readonly
Returns the value of attribute read_timeout.
-
#retry_backoff ⇒ Object
readonly
Returns the value of attribute retry_backoff.
-
#user_agent ⇒ Object
readonly
Returns the value of attribute user_agent.
Instance Method Summary collapse
- #delete(path, params: nil) ⇒ Object
-
#dictionaries(project: nil, languages: nil) ⇒ Object
Every language of one project, as { "en" => Dictionary, … }.
-
#dictionary(language:, project: nil) ⇒ Object
One language of one project as a flat key => value dictionary.
- #get(path, params: nil) ⇒ Object
-
#initialize(api_key: ENV.fetch("MULTILOCALE_API_KEY", nil), access_token: ENV.fetch("MULTILOCALE_ACCESS_TOKEN", nil), api_url: ENV.fetch("MULTILOCALE_API_URL", DEFAULT_API_URL), project: ENV.fetch("MULTILOCALE_PROJECT", nil), open_timeout: DEFAULT_OPEN_TIMEOUT, read_timeout: DEFAULT_READ_TIMEOUT, max_retries: DEFAULT_MAX_RETRIES, retry_backoff: DEFAULT_RETRY_BACKOFF, user_agent: nil, logger: nil) ⇒ Client
constructor
A new instance of Client.
-
#inspect ⇒ Object
(also: #to_s)
Never let a credential reach a log line, an exception report or
p client. - #phrases ⇒ Object
- #post(path, body:) ⇒ Object
-
#project_name(project_or_id) ⇒ Object
Accepts an id, a name or a Project and returns the name the phrases endpoints filter on — they match
projects(names), never ids. - #projects ⇒ Object
- #put(path, body:) ⇒ Object
- #request(method, path, params: nil, body: nil) ⇒ Object
Constructor Details
#initialize(api_key: ENV.fetch("MULTILOCALE_API_KEY", nil), access_token: ENV.fetch("MULTILOCALE_ACCESS_TOKEN", nil), api_url: ENV.fetch("MULTILOCALE_API_URL", DEFAULT_API_URL), project: ENV.fetch("MULTILOCALE_PROJECT", nil), open_timeout: DEFAULT_OPEN_TIMEOUT, read_timeout: DEFAULT_READ_TIMEOUT, max_retries: DEFAULT_MAX_RETRIES, retry_backoff: DEFAULT_RETRY_BACKOFF, user_agent: nil, logger: nil) ⇒ Client
Returns a new instance of Client.
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/multilocale/client.rb', line 46 def initialize( api_key: ENV.fetch("MULTILOCALE_API_KEY", nil), access_token: ENV.fetch("MULTILOCALE_ACCESS_TOKEN", nil), api_url: ENV.fetch("MULTILOCALE_API_URL", DEFAULT_API_URL), project: ENV.fetch("MULTILOCALE_PROJECT", nil), open_timeout: DEFAULT_OPEN_TIMEOUT, read_timeout: DEFAULT_READ_TIMEOUT, max_retries: DEFAULT_MAX_RETRIES, retry_backoff: DEFAULT_RETRY_BACKOFF, user_agent: nil, logger: nil ) api_key = nil if api_key.nil? || api_key.to_s.strip.empty? access_token = nil if access_token.nil? || access_token.to_s.strip.empty? if api_key.nil? && access_token.nil? raise ConfigurationError, <<~MESSAGE No Multilocale credential. Create an API key at https://app.multilocale.com/keys and export it: export MULTILOCALE_API_KEY=<the key secret> or pass one explicitly: Multilocale::Client.new(api_key: "…"). MESSAGE end @api_key = api_key @access_token = access_token @api_url = api_url.to_s.sub(%r{/+\z}, "") @project = project @open_timeout = open_timeout @read_timeout = read_timeout @max_retries = max_retries @retry_backoff = retry_backoff @user_agent = user_agent || "multilocale-ruby/#{VERSION} (ruby #{RUBY_VERSION})" @logger = logger end |
Instance Attribute Details
#api_url ⇒ Object (readonly)
Returns the value of attribute api_url.
39 40 41 |
# File 'lib/multilocale/client.rb', line 39 def api_url @api_url end |
#max_retries ⇒ Object (readonly)
Returns the value of attribute max_retries.
39 40 41 |
# File 'lib/multilocale/client.rb', line 39 def max_retries @max_retries end |
#open_timeout ⇒ Object (readonly)
Returns the value of attribute open_timeout.
39 40 41 |
# File 'lib/multilocale/client.rb', line 39 def open_timeout @open_timeout end |
#project ⇒ Object (readonly)
Returns the value of attribute project.
39 40 41 |
# File 'lib/multilocale/client.rb', line 39 def project @project end |
#read_timeout ⇒ Object (readonly)
Returns the value of attribute read_timeout.
39 40 41 |
# File 'lib/multilocale/client.rb', line 39 def read_timeout @read_timeout end |
#retry_backoff ⇒ Object (readonly)
Returns the value of attribute retry_backoff.
39 40 41 |
# File 'lib/multilocale/client.rb', line 39 def retry_backoff @retry_backoff end |
#user_agent ⇒ Object (readonly)
Returns the value of attribute user_agent.
39 40 41 |
# File 'lib/multilocale/client.rb', line 39 def user_agent @user_agent end |
Instance Method Details
#delete(path, params: nil) ⇒ Object
139 140 141 |
# File 'lib/multilocale/client.rb', line 139 def delete(path, params: nil) request(:delete, path, params: params) end |
#dictionaries(project: nil, languages: nil) ⇒ Object
Every language of one project, as { "en" => Dictionary, … }.
107 108 109 110 111 112 113 114 115 |
# File 'lib/multilocale/client.rb', line 107 def dictionaries(project: nil, languages: nil) rows = phrases.list(project: project_name(project || @project)) dictionaries = Dictionary.from_phrases(rows) return dictionaries if languages.nil? languages.each_with_object({}) do |language, selected| selected[language] = dictionaries[language] || Dictionary.new(language, {}) end end |
#dictionary(language:, project: nil) ⇒ Object
One language of one project as a flat key => value dictionary.
project: falls back to the client's own when it is nil, rather than
defaulting in the signature: callers forward an optional value here, and
project: nil would otherwise silently defeat the default.
98 99 100 101 102 103 104 |
# File 'lib/multilocale/client.rb', line 98 def dictionary(language:, project: nil) Dictionary.new( language, phrases.list(project: project_name(project || @project), language: language) .each_with_object({}) { |phrase, entries| entries[phrase.key] = phrase.value } ) end |
#get(path, params: nil) ⇒ Object
127 128 129 |
# File 'lib/multilocale/client.rb', line 127 def get(path, params: nil) request(:get, path, params: params) end |
#inspect ⇒ Object Also known as: to_s
Never let a credential reach a log line, an exception report or p client.
172 173 174 |
# File 'lib/multilocale/client.rb', line 172 def inspect "#<Multilocale::Client api_url=#{@api_url.inspect} auth=#{@api_key ? 'api_key' : 'access_token'} [redacted]>" end |
#phrases ⇒ Object
89 90 91 |
# File 'lib/multilocale/client.rb', line 89 def phrases @phrases ||= Phrases.new(self) end |
#post(path, body:) ⇒ Object
131 132 133 |
# File 'lib/multilocale/client.rb', line 131 def post(path, body:) request(:post, path, body: body) end |
#project_name(project_or_id) ⇒ Object
Accepts an id, a name or a Project and returns the name the phrases
endpoints filter on — they match projects (names), never ids.
119 120 121 122 123 124 125 |
# File 'lib/multilocale/client.rb', line 119 def project_name(project_or_id) raise ConfigurationError, "No project given, and no default project on the client." if project_or_id.nil? return project_or_id.name if project_or_id.is_a?(Project) return project_or_id unless project_or_id.to_s.match?(/\A[0-9a-f]{24}\z/) projects.find(project_or_id).name end |
#projects ⇒ Object
85 86 87 |
# File 'lib/multilocale/client.rb', line 85 def projects @projects ||= Projects.new(self) end |
#put(path, body:) ⇒ Object
135 136 137 |
# File 'lib/multilocale/client.rb', line 135 def put(path, body:) request(:put, path, body: body) end |
#request(method, path, params: nil, body: nil) ⇒ Object
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/multilocale/client.rb', line 143 def request(method, path, params: nil, body: nil) url = build_url(path, params) uri = URI.parse(url) attempt = 0 loop do attempt += 1 begin response = execute(method, uri, body) rescue *RETRIABLE_EXCEPTIONS => error raise ConnectionError, "#{method.to_s.upcase} #{url} failed: #{error.class}: #{error.}" if attempt > max_retries sleep(backoff_for(attempt)) next end status = response.code.to_i if RETRIABLE_STATUSES.include?(status) && attempt <= max_retries sleep(retry_after(response) || backoff_for(attempt)) next end return parse(response, method: method, url: url) end end |