Class: ApiBrasil::Core::HttpClient
- Inherits:
-
Object
- Object
- ApiBrasil::Core::HttpClient
- Defined in:
- lib/api_brasil/core/http_client.rb
Overview
Cliente HTTP interno da SDK. Injeta os headers de autenticacao da
plataforma (Authorization: Bearer, DeviceToken, SecretKey),
aplica retry com backoff, dispara hooks de observabilidade e converte
falhas em subclasses de ApiBrasilError.
Chaves de configuracao aceitas (tambem aceitas em camelCase):
bearer_token(String): token JWT obtido no logindevice_token(String): token do dispositivo (servicos device-based)secret_key(String): SecretKey da API (usada ao criar devices)base_url(String): base da API. Padrao:https://gateway.apibrasil.io/api/v2timeout(Integer): timeout das requisicoes em milissegundos. Padrao: 30000headers(Hash): headers adicionais em todas as requisicoestransport(Transport::Base): transporte customizadoretry(Hash, false): politica de retry - vejaRetry::DEFAULThooks(Hash):on_request,on_response,on_retry(callables)
Opcoes por requisicao (options), que sobrescrevem a configuracao:
query, headers, bearer_token, device_token, secret_key, timeout,
response_type (json | raw | stream).
Constant Summary collapse
- DEFAULT_BASE_URL =
"https://gateway.apibrasil.io/api/v2"- DEFAULT_TIMEOUT =
30_000- SDK_USER_AGENT =
"APIBRASIL/SDK-RUBY #{ApiBrasil::VERSION}".freeze
Instance Attribute Summary collapse
- #hooks ⇒ Hash{Symbol => Proc} readonly
-
#retry_config ⇒ Hash?
readonly
Politica de retry resolvida (
nilquando desligada). - #transport ⇒ Transport::Base readonly
Class Method Summary collapse
- .build_query_string(query) ⇒ String
-
.encode_body(body) ⇒ String
Serializa o corpo em JSON.
-
.escape_path_segment(value) ⇒ String
Escapa um valor usado como segmento de path (
%20, nao+). - .join_url(base_url, path) ⇒ String
- .normalize_key(key) ⇒ Symbol
-
.normalize_keys(hash) ⇒ Hash{Symbol => Object}
Converte chaves camelCase/String para simbolos snake_case, mantendo a paridade com as SDKs PHP/Node/Dart (
baseURL,bearerToken...).
Instance Method Summary collapse
- #base_url ⇒ String
- #bearer_token ⇒ String?
-
#bearer_token=(token) ⇒ Object
(also: #set_bearer_token)
Define/atualiza o Bearer Token (
nilremove). - #delete(path, body = nil, options = {}) ⇒ Object
- #device_token ⇒ String?
-
#device_token=(token) ⇒ Object
(also: #set_device_token)
Define/atualiza o DeviceToken (
nilremove). - #get(path, options = {}) ⇒ Object
-
#initialize(config = {}) ⇒ HttpClient
constructor
A new instance of HttpClient.
- #patch(path, body = nil, options = {}) ⇒ Object
- #post(path, body = nil, options = {}) ⇒ Object
- #put(path, body = nil, options = {}) ⇒ Object
-
#request(method, path, body = nil, options = {}) ⇒ Object
Executa uma requisicao no gateway.
- #secret_key ⇒ String?
-
#to_config ⇒ Hash
Configuracao atual do cliente (util para clonar com outro device).
Constructor Details
#initialize(config = {}) ⇒ HttpClient
Returns a new instance of HttpClient.
48 49 50 51 52 53 54 55 56 57 |
# File 'lib/api_brasil/core/http_client.rb', line 48 def initialize(config = {}) config = self.class.normalize_keys(config) @config = Env.config.merge(config.compact) transport = @config[:transport] @transport = transport.respond_to?(:request) ? transport : Transport.default @retry_config = Retry.resolve(@config.key?(:retry) ? @config[:retry] : nil) @hooks = self.class.normalize_keys(@config[:hooks] || {}) end |
Instance Attribute Details
#hooks ⇒ Hash{Symbol => Proc} (readonly)
45 46 47 |
# File 'lib/api_brasil/core/http_client.rb', line 45 def hooks @hooks end |
#retry_config ⇒ Hash? (readonly)
Returns politica de retry resolvida (nil quando desligada).
42 43 44 |
# File 'lib/api_brasil/core/http_client.rb', line 42 def retry_config @retry_config end |
#transport ⇒ Transport::Base (readonly)
39 40 41 |
# File 'lib/api_brasil/core/http_client.rb', line 39 def transport @transport end |
Class Method Details
.build_query_string(query) ⇒ String
195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/api_brasil/core/http_client.rb', line 195 def self.build_query_string(query) return "" if query.nil? || !query.is_a?(Hash) || query.empty? parts = query.filter_map do |key, value| next if value.nil? value = value.join(",") if value.is_a?(Array) "#{URI.encode_www_form_component(key.to_s)}=#{URI.encode_www_form_component(value.to_s)}" end parts.empty? ? "" : "?#{parts.join("&")}" end |
.encode_body(body) ⇒ String
Serializa o corpo em JSON. Hashes vazios viram {} (objeto), como
nas demais SDKs, e nunca [].
186 187 188 189 190 191 |
# File 'lib/api_brasil/core/http_client.rb', line 186 def self.encode_body(body) return body if body.is_a?(String) return "{}" if body.respond_to?(:empty?) && body.empty? JSON.generate(body) end |
.escape_path_segment(value) ⇒ String
Escapa um valor usado como segmento de path (%20, nao +).
211 212 213 |
# File 'lib/api_brasil/core/http_client.rb', line 211 def self.escape_path_segment(value) URI.encode_www_form_component(value.to_s).gsub("+", "%20") end |
.join_url(base_url, path) ⇒ String
216 217 218 219 220 221 |
# File 'lib/api_brasil/core/http_client.rb', line 216 def self.join_url(base_url, path) base = base_url.to_s.sub(%r{/+\z}, "") suffix = path.to_s.sub(%r{\A/+}, "") suffix.empty? ? base : "#{base}/#{suffix}" end |
.normalize_key(key) ⇒ Symbol
178 179 180 |
# File 'lib/api_brasil/core/http_client.rb', line 178 def self.normalize_key(key) key.to_s.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase.to_sym end |
.normalize_keys(hash) ⇒ Hash{Symbol => Object}
Converte chaves camelCase/String para simbolos snake_case, mantendo
a paridade com as SDKs PHP/Node/Dart (baseURL, bearerToken...).
168 169 170 171 172 173 174 175 |
# File 'lib/api_brasil/core/http_client.rb', line 168 def self.normalize_keys(hash) return {} if hash.nil? return hash unless hash.is_a?(Hash) hash.each_with_object({}) do |(key, value), acc| acc[normalize_key(key)] = value end end |
Instance Method Details
#base_url ⇒ String
60 61 62 63 |
# File 'lib/api_brasil/core/http_client.rb', line 60 def base_url value = @config[:base_url] value.is_a?(String) && !value.empty? ? value : DEFAULT_BASE_URL end |
#bearer_token ⇒ String?
66 67 68 69 |
# File 'lib/api_brasil/core/http_client.rb', line 66 def bearer_token value = @config[:bearer_token] value.is_a?(String) ? value : nil end |
#bearer_token=(token) ⇒ Object Also known as: set_bearer_token
Define/atualiza o Bearer Token (nil remove).
84 85 86 87 88 89 90 |
# File 'lib/api_brasil/core/http_client.rb', line 84 def bearer_token=(token) if token.nil? @config.delete(:bearer_token) else @config[:bearer_token] = token end end |
#delete(path, body = nil, options = {}) ⇒ Object
159 160 161 |
# File 'lib/api_brasil/core/http_client.rb', line 159 def delete(path, body = nil, = {}) request("DELETE", path, body, ) end |
#device_token ⇒ String?
72 73 74 75 |
# File 'lib/api_brasil/core/http_client.rb', line 72 def device_token value = @config[:device_token] value.is_a?(String) ? value : nil end |
#device_token=(token) ⇒ Object Also known as: set_device_token
Define/atualiza o DeviceToken (nil remove).
94 95 96 97 98 99 100 |
# File 'lib/api_brasil/core/http_client.rb', line 94 def device_token=(token) if token.nil? @config.delete(:device_token) else @config[:device_token] = token end end |
#get(path, options = {}) ⇒ Object
139 140 141 |
# File 'lib/api_brasil/core/http_client.rb', line 139 def get(path, = {}) request("GET", path, nil, ) end |
#patch(path, body = nil, options = {}) ⇒ Object
154 155 156 |
# File 'lib/api_brasil/core/http_client.rb', line 154 def patch(path, body = nil, = {}) request("PATCH", path, body, ) end |
#post(path, body = nil, options = {}) ⇒ Object
144 145 146 |
# File 'lib/api_brasil/core/http_client.rb', line 144 def post(path, body = nil, = {}) request("POST", path, body, ) end |
#put(path, body = nil, options = {}) ⇒ Object
149 150 151 |
# File 'lib/api_brasil/core/http_client.rb', line 149 def put(path, body = nil, = {}) request("PUT", path, body, ) end |
#request(method, path, body = nil, options = {}) ⇒ Object
Executa uma requisicao no gateway.
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/api_brasil/core/http_client.rb', line 117 def request(method, path, body = nil, = {}) = self.class.normalize_keys() transport_request = build_transport_request(method, path, body, ) attempt = 0 loop do response = perform(transport_request, body, attempt) return response.data if response.status < 400 error = Errors::ErrorFactory.create(response.status, response.data, response.headers) raise error unless retry_status?(response.status, attempt) attempt = wait_and_bump(attempt, transport_request, "HTTP #{response.status}", suggested_delay(error, attempt)) rescue Errors::NetworkError => e raise Errors::ApiBrasilError.from(e) unless retry_error?(e, attempt) attempt = wait_and_bump(attempt, transport_request, e.) end end |
#secret_key ⇒ String?
78 79 80 81 |
# File 'lib/api_brasil/core/http_client.rb', line 78 def secret_key value = @config[:secret_key] value.is_a?(String) ? value : nil end |
#to_config ⇒ Hash
Configuracao atual do cliente (util para clonar com outro device).
106 107 108 |
# File 'lib/api_brasil/core/http_client.rb', line 106 def to_config @config.merge(transport: @transport) end |