apigratis-sdk-ruby 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +27 -0
- data/LICENSE +21 -0
- data/README.md +330 -0
- data/SECURITY.md +32 -0
- data/lib/api_brasil/client.rb +252 -0
- data/lib/api_brasil/core/env.rb +34 -0
- data/lib/api_brasil/core/errors.rb +167 -0
- data/lib/api_brasil/core/http_client.rb +342 -0
- data/lib/api_brasil/core/retry.rb +69 -0
- data/lib/api_brasil/core/transport/faraday_transport.rb +76 -0
- data/lib/api_brasil/core/transport/net_http_transport.rb +126 -0
- data/lib/api_brasil/core/transport.rb +114 -0
- data/lib/api_brasil/generated/catalog.rb +526 -0
- data/lib/api_brasil/legacy/service.rb +155 -0
- data/lib/api_brasil/services/base_service.rb +49 -0
- data/lib/api_brasil/services/data/bulk_service.rb +26 -0
- data/lib/api_brasil/services/data/cep_service.rb +58 -0
- data/lib/api_brasil/services/data/chip_virtual_service.rb +40 -0
- data/lib/api_brasil/services/data/consulta_service.rb +97 -0
- data/lib/api_brasil/services/data/correios_service.rb +23 -0
- data/lib/api_brasil/services/data/dados_service.rb +30 -0
- data/lib/api_brasil/services/data/database_ip_service.rb +19 -0
- data/lib/api_brasil/services/data/fipe_service.rb +61 -0
- data/lib/api_brasil/services/data/proxies.rb +146 -0
- data/lib/api_brasil/services/data/ura_service.rb +26 -0
- data/lib/api_brasil/services/data/vehicles_service.rb +46 -0
- data/lib/api_brasil/services/device_proxy_service.rb +46 -0
- data/lib/api_brasil/services/messaging/evolution_service.rb +38 -0
- data/lib/api_brasil/services/messaging/sms_service.rb +40 -0
- data/lib/api_brasil/services/messaging/whats_meow_service.rb +30 -0
- data/lib/api_brasil/services/messaging/whatsapp_service.rb +120 -0
- data/lib/api_brasil/services/platform/account_service.rb +138 -0
- data/lib/api_brasil/services/platform/auth_service.rb +204 -0
- data/lib/api_brasil/services/platform/bearer_rate_limit_service.rb +29 -0
- data/lib/api_brasil/services/platform/catalog_service.rb +111 -0
- data/lib/api_brasil/services/platform/devices_service.rb +73 -0
- data/lib/api_brasil/services/platform/ip_whitelist_service.rb +73 -0
- data/lib/api_brasil/services/platform/payments_service.rb +124 -0
- data/lib/api_brasil/services/platform/reports_service.rb +96 -0
- data/lib/api_brasil/version.rb +6 -0
- data/lib/api_brasil.rb +72 -0
- data/lib/apigratis-sdk-ruby.rb +5 -0
- data/lib/apigratis.rb +11 -0
- metadata +149 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "openssl"
|
|
5
|
+
require "timeout"
|
|
6
|
+
require "uri"
|
|
7
|
+
require "json"
|
|
8
|
+
|
|
9
|
+
module ApiBrasil
|
|
10
|
+
module Core
|
|
11
|
+
module Transport
|
|
12
|
+
# Transporte padrao, sem dependencias: usa apenas `net/http` da stdlib.
|
|
13
|
+
class NetHttpTransport < Base
|
|
14
|
+
# Verbos suportados -> classe de requisicao do `net/http`.
|
|
15
|
+
METHODS = {
|
|
16
|
+
"GET" => Net::HTTP::Get,
|
|
17
|
+
"HEAD" => Net::HTTP::Head,
|
|
18
|
+
"POST" => Net::HTTP::Post,
|
|
19
|
+
"PUT" => Net::HTTP::Put,
|
|
20
|
+
"PATCH" => Net::HTTP::Patch,
|
|
21
|
+
"DELETE" => Net::HTTP::Delete
|
|
22
|
+
}.freeze
|
|
23
|
+
|
|
24
|
+
# Limite de redirecionamentos seguidos automaticamente.
|
|
25
|
+
MAX_REDIRECTS = 5
|
|
26
|
+
|
|
27
|
+
# Erros de conexao tratados como `NetworkError`.
|
|
28
|
+
NETWORK_ERRORS = [
|
|
29
|
+
SocketError,
|
|
30
|
+
IOError,
|
|
31
|
+
SystemCallError,
|
|
32
|
+
OpenSSL::SSL::SSLError,
|
|
33
|
+
Net::HTTPBadResponse,
|
|
34
|
+
Net::ProtocolError
|
|
35
|
+
].freeze
|
|
36
|
+
|
|
37
|
+
# @param options [Hash] opcoes extras do `Net::HTTP`
|
|
38
|
+
# (ex: `proxy_address`, `proxy_port`, `verify_mode`, `ca_file`)
|
|
39
|
+
def initialize(options = {})
|
|
40
|
+
super()
|
|
41
|
+
@options = options || {}
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# @param request [Request]
|
|
45
|
+
# @return [Response]
|
|
46
|
+
def request(request)
|
|
47
|
+
perform(request, request.url, MAX_REDIRECTS)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def perform(request, url, redirects_left)
|
|
53
|
+
uri = URI.parse(url)
|
|
54
|
+
response = execute(request, uri)
|
|
55
|
+
|
|
56
|
+
if redirect?(response.code.to_i) && redirects_left.positive?
|
|
57
|
+
location = response["location"]
|
|
58
|
+
return perform(request, URI.join(url, location).to_s, redirects_left - 1) if location
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
Response.new(
|
|
62
|
+
response.code.to_i,
|
|
63
|
+
normalize_headers(response),
|
|
64
|
+
Transport.decode_body(request, response.body)
|
|
65
|
+
)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def execute(request, uri)
|
|
69
|
+
http = build_http(uri, request.timeout_ms)
|
|
70
|
+
http.request(build_net_request(request, uri))
|
|
71
|
+
rescue Timeout::Error => e # Net::OpenTimeout, Net::ReadTimeout e Net::WriteTimeout herdam daqui
|
|
72
|
+
raise Errors::TimeoutError.new(
|
|
73
|
+
"Tempo limite de #{request.timeout_ms.to_i}ms excedido em #{request.method} #{uri}.",
|
|
74
|
+
previous: e
|
|
75
|
+
)
|
|
76
|
+
rescue *NETWORK_ERRORS => e
|
|
77
|
+
raise Errors::NetworkError.new(
|
|
78
|
+
"Falha de rede em #{request.method} #{uri}: #{e.message}",
|
|
79
|
+
previous: e
|
|
80
|
+
)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def build_http(uri, timeout_ms)
|
|
84
|
+
# `:ENV` mantem o comportamento padrao de respeitar http_proxy/https_proxy.
|
|
85
|
+
proxy_address = @options.key?(:proxy_address) ? @options[:proxy_address] : :ENV
|
|
86
|
+
http = Net::HTTP.new(uri.host, uri.port, proxy_address, @options[:proxy_port],
|
|
87
|
+
@options[:proxy_user], @options[:proxy_pass])
|
|
88
|
+
http.use_ssl = uri.scheme == "https"
|
|
89
|
+
http.verify_mode = @options[:verify_mode] if @options.key?(:verify_mode)
|
|
90
|
+
http.ca_file = @options[:ca_file] if @options[:ca_file]
|
|
91
|
+
|
|
92
|
+
if timeout_ms.to_i.positive?
|
|
93
|
+
seconds = timeout_ms.to_f / 1000
|
|
94
|
+
http.open_timeout = seconds
|
|
95
|
+
http.read_timeout = seconds
|
|
96
|
+
http.write_timeout = seconds if http.respond_to?(:write_timeout=)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
http
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def build_net_request(request, uri)
|
|
103
|
+
klass = METHODS[request.method]
|
|
104
|
+
raise Errors::NetworkError, "Metodo HTTP nao suportado: #{request.method}" if klass.nil?
|
|
105
|
+
|
|
106
|
+
path = uri.request_uri
|
|
107
|
+
net_request = klass.new(path)
|
|
108
|
+
request.headers.each { |name, value| net_request[name.to_s] = value.to_s }
|
|
109
|
+
net_request.body = request.body unless request.body.nil?
|
|
110
|
+
|
|
111
|
+
net_request
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def redirect?(status)
|
|
115
|
+
[301, 302, 303, 307, 308].include?(status)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def normalize_headers(response)
|
|
119
|
+
response.each_header.with_object({}) do |(name, value), acc|
|
|
120
|
+
acc[name.to_s.downcase] = value
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
require_relative "errors"
|
|
6
|
+
|
|
7
|
+
module ApiBrasil
|
|
8
|
+
module Core
|
|
9
|
+
# Camada de transporte HTTP da SDK. A implementacao padrao usa a stdlib
|
|
10
|
+
# (`NetHttpTransport`), com uso automatico do Faraday quando ele ja esta
|
|
11
|
+
# carregado no processo (`FaradayTransport`); injete a sua para usar
|
|
12
|
+
# proxies, outro cliente HTTP, mocks de teste etc.
|
|
13
|
+
#
|
|
14
|
+
# Contrato: retorna a resposta para QUALQUER status HTTP; lanca
|
|
15
|
+
# `NetworkError`/`TimeoutError` apenas quando nao houve resposta.
|
|
16
|
+
module Transport
|
|
17
|
+
# Requisicao entregue a camada de transporte - ja com URL absoluta,
|
|
18
|
+
# headers montados e corpo serializado.
|
|
19
|
+
class Request
|
|
20
|
+
# @return [String] verbo HTTP em maiusculas
|
|
21
|
+
attr_reader :method
|
|
22
|
+
|
|
23
|
+
# @return [String] URL absoluta
|
|
24
|
+
attr_reader :url
|
|
25
|
+
|
|
26
|
+
# @return [Hash{String => String}]
|
|
27
|
+
attr_reader :headers
|
|
28
|
+
|
|
29
|
+
# @return [String, nil] corpo ja serializado (JSON)
|
|
30
|
+
attr_reader :body
|
|
31
|
+
|
|
32
|
+
# @return [Integer, nil] timeout em milissegundos
|
|
33
|
+
attr_reader :timeout_ms
|
|
34
|
+
|
|
35
|
+
# @return [String, nil] `json` (padrao), `raw`/`arraybuffer` ou `stream`
|
|
36
|
+
attr_reader :response_type
|
|
37
|
+
|
|
38
|
+
def initialize(method, url, headers: {}, body: nil, timeout_ms: nil, response_type: nil)
|
|
39
|
+
@method = method.to_s.upcase
|
|
40
|
+
@url = url
|
|
41
|
+
@headers = headers || {}
|
|
42
|
+
@body = body
|
|
43
|
+
@timeout_ms = timeout_ms
|
|
44
|
+
@response_type = response_type
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Resposta devolvida pela camada de transporte.
|
|
49
|
+
class Response
|
|
50
|
+
# @return [Integer]
|
|
51
|
+
attr_reader :status
|
|
52
|
+
|
|
53
|
+
# @return [Hash{String => String}] headers com nomes em minusculas
|
|
54
|
+
attr_reader :headers
|
|
55
|
+
|
|
56
|
+
# @return [Object] corpo ja decodificado (JSON -> Hash; texto; binario)
|
|
57
|
+
attr_reader :data
|
|
58
|
+
|
|
59
|
+
def initialize(status, headers = {}, data = nil)
|
|
60
|
+
@status = status
|
|
61
|
+
@headers = headers || {}
|
|
62
|
+
@data = data
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Interface do transporte. Implemente `#request` recebendo um
|
|
67
|
+
# `Transport::Request` e devolvendo um `Transport::Response`.
|
|
68
|
+
class Base
|
|
69
|
+
# @param _request [Request]
|
|
70
|
+
# @return [Response]
|
|
71
|
+
def request(_request)
|
|
72
|
+
raise NotImplementedError, "#{self.class}#request precisa ser implementado."
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Tipos de resposta que nao devem ser decodificados como JSON.
|
|
77
|
+
RAW_RESPONSE_TYPES = %w[raw arraybuffer stream].freeze
|
|
78
|
+
|
|
79
|
+
module_function
|
|
80
|
+
|
|
81
|
+
# Transporte padrao: Faraday quando ja carregado, senao `net/http`.
|
|
82
|
+
#
|
|
83
|
+
# @return [Base]
|
|
84
|
+
def default
|
|
85
|
+
return FaradayTransport.new if defined?(::Faraday)
|
|
86
|
+
|
|
87
|
+
NetHttpTransport.new
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Decodifica o corpo conforme o `response_type` pedido.
|
|
91
|
+
#
|
|
92
|
+
# @param request [Request]
|
|
93
|
+
# @param raw [String, nil]
|
|
94
|
+
# @return [Object, nil]
|
|
95
|
+
def decode_body(request, raw)
|
|
96
|
+
return raw if RAW_RESPONSE_TYPES.include?(request.response_type)
|
|
97
|
+
return nil if raw.nil? || raw.empty?
|
|
98
|
+
|
|
99
|
+
begin
|
|
100
|
+
JSON.parse(raw)
|
|
101
|
+
rescue JSON::ParserError
|
|
102
|
+
raw
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Aliases com os mesmos nomes usados nas SDKs PHP/Node/Go/Dart.
|
|
108
|
+
TransportRequest = Transport::Request
|
|
109
|
+
TransportResponse = Transport::Response
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
require_relative "transport/net_http_transport"
|
|
114
|
+
require_relative "transport/faraday_transport"
|