Class: Axene::Mailer::Transport
- Inherits:
-
Object
- Object
- Axene::Mailer::Transport
- Defined in:
- lib/axene/mailer/transport.rb
Overview
HTTP transport: the single place that talks to the network. Owns bearer authentication, JSON encode/decode, timeouts, retries with backoff, and turning non-2xx responses into Error. Resources depend on this, not on Net::HTTP directly.
Constant Summary collapse
- DEFAULT_BASE_URL =
"https://mail.axene.io"- USER_AGENT =
"axene-mailer-ruby/#{VERSION}"
Instance Method Summary collapse
-
#initialize(api_key:, base_url: DEFAULT_BASE_URL, max_retries: 3, timeout: 30) ⇒ Transport
constructor
A new instance of Transport.
-
#request(method, path, body: nil, query: nil) ⇒ Hash, ...
Perform a JSON request and return the parsed body (symbolized keys).
-
#upload(path, file_bytes, filename) ⇒ Hash, ...
Upload a single file as multipart/form-data under the field name “file”.
Constructor Details
#initialize(api_key:, base_url: DEFAULT_BASE_URL, max_retries: 3, timeout: 30) ⇒ Transport
Returns a new instance of Transport.
24 25 26 27 28 29 30 31 |
# File 'lib/axene/mailer/transport.rb', line 24 def initialize(api_key:, base_url: DEFAULT_BASE_URL, max_retries: 3, timeout: 30) raise ArgumentError, "Axene::Mailer: `api_key` is required." if api_key.nil? || api_key.empty? @api_key = api_key @base_url = base_url.sub(%r{/+\z}, "") @max_retries = max_retries @timeout = timeout end |
Instance Method Details
#request(method, path, body: nil, query: nil) ⇒ Hash, ...
Perform a JSON request and return the parsed body (symbolized keys).
Retries 429 and 5xx with exponential backoff, honoring Retry-After when present. Raises Error on a final non-2xx or a transport failure that survives every attempt.
44 45 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 |
# File 'lib/axene/mailer/transport.rb', line 44 def request(method, path, body: nil, query: nil) uri = build_uri(path, query) last_error = nil (1..@max_retries).each do |attempt| req = build_request(method, uri) unless body.nil? req["Content-Type"] = "application/json" req.body = JSON.generate(body) end begin res = http(uri).request(req) rescue StandardError => e last_error = e sleep(backoff_seconds(nil, attempt)) if attempt < @max_retries next end status = res.code.to_i if retryable?(status) && attempt < @max_retries sleep(backoff_seconds(res, attempt)) next end payload = parse_body(res) raise to_error(status, payload) unless status.between?(200, 299) return payload end raise Error.new(0, "Axene::Mailer request failed: #{last_error}") end |
#upload(path, file_bytes, filename) ⇒ Hash, ...
Upload a single file as multipart/form-data under the field name “file”. Used by the CSV/suppression import endpoints. Not retried (uploads are not idempotent).
86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/axene/mailer/transport.rb', line 86 def upload(path, file_bytes, filename) uri = build_uri(path, nil) boundary = "AxeneBoundary#{SecureRandom.hex(16)}" req = build_request(:post, uri) req["Content-Type"] = "multipart/form-data; boundary=#{boundary}" req.body = multipart_body(boundary, file_bytes, filename) res = http(uri).request(req) status = res.code.to_i payload = parse_body(res) raise to_error(status, payload) unless status.between?(200, 299) payload end |