Class: LabelZoom::Client
- Inherits:
-
Object
- Object
- LabelZoom::Client
- Defined in:
- lib/labelzoom/client.rb
Overview
Converts labels through the LabelZoom API.
Authentication is optional. Without a credential the API serves a free tier: watermarked output, the first label only, a 1 MB request cap, and no multi-page, JSON-target or image-to-image conversion. Constructing a client with no key is therefore a supported, tested path rather than an error.
Constant Summary collapse
- DEFAULT_BASE_URL =
The production API host.
"https://api.labelzoom.com"- API_KEY_ENVIRONMENT_VARIABLE =
The environment variable consulted when no credential is configured.
"LABELZOOM_API_KEY"- REQUEST_ID_HEADER =
The support handle the gateway stamps on every response. Net::HTTP looks headers up case-insensitively, which matters here: the gateway sets X-LZ-Request-Id but CORS exposes it as X-LZ-Request-ID.
"x-lz-request-id"- MAX_MESSAGE_LENGTH =
E2 caps the derived message here. APIError#raw_body keeps the whole body.
512- RETRYABLE_STATUSES =
Statuses worth retrying. Rule F1: nothing else, ever.
->(status) { status == 429 || status >= 500 }
- REASON_PHRASES =
E2's last resort, when a body is empty and the reason phrase is too. Net::HTTP does not always surface a phrase, so this is derived from a table rather than the wire.
{ 400 => "Bad Request", 401 => "Unauthorized", 403 => "Forbidden", 404 => "Not Found", 406 => "Not Acceptable", 413 => "Payload Too Large", 429 => "Too Many Requests", 500 => "Internal Server Error", 502 => "Bad Gateway", 503 => "Service Unavailable", 504 => "Gateway Timeout" }.freeze
Instance Method Summary collapse
-
#authenticated? ⇒ Boolean
Whether a credential was resolved.
-
#build_uri(source, target, params = nil) ⇒ Object
The URL a given conversion would be posted to.
-
#convert(source, target, body, base64_text: false, **options) ⇒ ConversionResult
Runs one conversion.
-
#initialize(api_key: UNSET, base_url: DEFAULT_BASE_URL, max_retries: 2, timeout: 60, user_agent_suffix: nil, sleeper: nil, jitter: true, env: ENV, http_builder: nil) ⇒ Client
constructor
A new instance of Client.
Constructor Details
#initialize(api_key: UNSET, base_url: DEFAULT_BASE_URL, max_retries: 2, timeout: 60, user_agent_suffix: nil, sleeper: nil, jitter: true, env: ENV, http_builder: nil) ⇒ Client
Returns a new instance of Client.
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/labelzoom/client.rb', line 60 def initialize(api_key: UNSET, base_url: DEFAULT_BASE_URL, max_retries: 2, timeout: 60, user_agent_suffix: nil, sleeper: nil, jitter: true, env: ENV, http_builder: nil) raise ArgumentError, "max_retries cannot be negative" if max_retries.negative? # All trailing slashes, not one: a base URL of "https://api.labelzoom.com///" must # still produce a single-slash path. @base_url = base_url.to_s.sub(%r{/+\z}, "") @credential = resolve_credential(api_key, env) @max_retries = max_retries @timeout = timeout @sleeper = sleeper || ->(seconds) { Kernel.sleep(seconds) } @jitter = jitter @http_builder = http_builder # The server parses a "LabelZoomStudio/" User-Agent prefix as a Studio version and # silently changes PDF handling for versions <= 1.8.2, so the SDK's own token must # come first. suffix = user_agent_suffix.to_s.strip @user_agent = "labelzoom-ruby-sdk/#{VERSION} (ruby/#{RUBY_VERSION})" @user_agent += " #{suffix}" unless suffix.empty? end |
Instance Method Details
#authenticated? ⇒ Boolean
Whether a credential was resolved. False means requests go out on the anonymous free tier, which is a supported mode rather than an error.
85 |
# File 'lib/labelzoom/client.rb', line 85 def authenticated? = !@credential.nil? |
#build_uri(source, target, params = nil) ⇒ Object
The URL a given conversion would be posted to. Exposed because it is the first thing anyone debugging a proxy or a base-URL override wants to see.
127 128 129 130 131 132 133 134 135 |
# File 'lib/labelzoom/client.rb', line 127 def build_uri(source, target, params = nil) # Concatenated, not resolved: a base URL carrying a path prefix # (https://proxy.example.com/labelzoom) must keep it, which URI.join would discard. url = "#{@base_url}/api/v2/convert/#{Formats.source_token(source)}/to/" \ "#{Formats.target_token(target)}" # Rule C7: no options means a bare URL, not an empty query string. url += "?#{URI.encode_www_form("params" => params)}" unless params.nil? URI.parse(url) end |
#convert(source, target, body, base64_text: false, **options) ⇒ ConversionResult
Runs one conversion.
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/labelzoom/client.rb', line 105 def convert(source, target, body, base64_text: false, **) source = Formats.source!(source) target = Formats.target!(target) body = body.to_s if body.empty? # The gateway rejects a zero-length body with 400; catching it here saves a round # trip and gives a clearer message. raise ValidationError.new("body", "Source body cannot be empty; the API rejects zero-length " \ "requests.") end params = Options.serialize(**) uri = build_uri(source, target, params) headers = build_headers(source, base64_text) execute(uri, headers, body) end |