Class: Backlex::Client
- Inherits:
-
Object
- Object
- Backlex::Client
- Defined in:
- lib/backlex/client.rb
Overview
The official Ruby client for the backlex API — a thin, typed wrapper over the same REST + SSE surface the TypeScript SDK (@backlex/client) speaks. Three auth modes: server key, workspace app mode (token capture), or cookie session.
Instance Attribute Summary collapse
-
#app_token ⇒ Object
Returns the value of attribute app_token.
-
#org ⇒ Object
Act inside a specific organization (slug or id) from here on, so
$org.idin permission rules resolves without threading it through every call. -
#workspace ⇒ Object
readonly
Returns the value of attribute workspace.
Class Method Summary collapse
-
.build_search(query) ⇒ Object
Serialize a ListQuery hash into a URL query string (mirrors buildSearch in index.ts).
-
.make_traceparent ⇒ Object
A W3C traceparent: 00-<32-hex trace id>-<16-hex span id>-01.
Instance Method Summary collapse
- #auth ⇒ Object
-
#auth_header(req) ⇒ Object
The one chokepoint every request path goes through (data, storage, realtime) — a header added here reaches every call.
-
#from(slug) ⇒ Object
CRUD handle for a collection.
-
#get_raw(path) ⇒ Object
Raw byte download (storage).
-
#initialize(url, api_key: nil, workspace: nil, token: nil, tenant: nil, org: nil, tracing: true) ⇒ Client
constructor
A new instance of Client.
-
#put_raw(path, body, content_type) ⇒ Object
Raw-body upload (storage).
-
#request(method, path, body = nil) ⇒ Object
Raw escape hatch — issues a JSON request with auth headers applied.
- #storage ⇒ Object
-
#subscribe(channel, on_event, on_error = nil) ⇒ Object
Subscribe to a realtime channel (e.g. "items:posts").
Constructor Details
#initialize(url, api_key: nil, workspace: nil, token: nil, tenant: nil, org: nil, tracing: true) ⇒ Client
Returns a new instance of Client.
20 21 22 23 24 25 26 27 28 |
# File 'lib/backlex/client.rb', line 20 def initialize(url, api_key: nil, workspace: nil, token: nil, tenant: nil, org: nil, tracing: true) @url = url.chomp("/") @api_key = api_key @workspace = workspace @app_token = token @tenant = tenant @org = org @tracing = tracing end |
Instance Attribute Details
#app_token ⇒ Object
Returns the value of attribute app_token.
14 15 16 |
# File 'lib/backlex/client.rb', line 14 def app_token @app_token end |
#org ⇒ Object
Act inside a specific organization (slug or id) from here on, so $org.id
in permission rules resolves without threading it through every call.
18 19 20 |
# File 'lib/backlex/client.rb', line 18 def org @org end |
#workspace ⇒ Object (readonly)
Returns the value of attribute workspace.
13 14 15 |
# File 'lib/backlex/client.rb', line 13 def workspace @workspace end |
Class Method Details
.build_search(query) ⇒ Object
Serialize a ListQuery hash into a URL query string (mirrors buildSearch in index.ts). The filter is compact JSON, percent-encoded exactly once.
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/backlex/client.rb', line 114 def self.build_search(query) return "" if query.nil? parts = [] if query[:filter] && !query[:filter].empty? parts << "filter=#{URI.encode_www_form_component(JSON.generate(query[:filter]))}" end # sort/fields may be absent when a hand-built query (e.g. one(id, expand:)) is # passed rather than a full builder-produced ListQuery — default to []. parts << "sort=#{URI.encode_www_form_component(query[:sort].join(','))}" unless (query[:sort] || []).empty? parts << "fields=#{URI.encode_www_form_component(query[:fields].join(','))}" unless (query[:fields] || []).empty? unless (query[:expand] || []).empty? parts << "expand=#{URI.encode_www_form_component(query[:expand].join(','))}" end parts << "limit=#{query[:limit]}" unless query[:limit].nil? parts << "offset=#{query[:offset]}" unless query[:offset].nil? parts << "meta=#{URI.encode_www_form_component(query[:meta])}" if query[:meta] parts << "locale=#{URI.encode_www_form_component(query[:locale])}" if query[:locale] parts << "q=#{URI.encode_www_form_component(query[:q])}" if query[:q] parts.empty? ? "" : "?#{parts.join('&')}" end |
.make_traceparent ⇒ Object
A W3C traceparent: 00-<32-hex trace id>-<16-hex span id>-01. Mirrors packages/client/src/trace.ts, which is what the API parses. Fresh per request — a span id reused across calls collapses them into one span.
33 34 35 |
# File 'lib/backlex/client.rb', line 33 def self.make_traceparent "00-#{SecureRandom.hex(16)}-#{SecureRandom.hex(8)}-01" end |
Instance Method Details
#auth ⇒ Object
42 43 44 |
# File 'lib/backlex/client.rb', line 42 def auth @auth ||= Auth.new(self) end |
#auth_header(req) ⇒ Object
The one chokepoint every request path goes through (data, storage, realtime) — a header added here reaches every call.
99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/backlex/client.rb', line 99 def auth_header(req) if @api_key req["Authorization"] = "Bearer #{@api_key}" elsif @app_token req["Authorization"] = "Bearer #{@app_token}" end req["X-Backlex-Tenant"] = @tenant if @tenant req["X-Backlex-Org"] = @org if @org # Without this a call never appears in the admin Traces panel and cannot # be stitched to the server spans it triggers. req["traceparent"] = self.class.make_traceparent if @tracing end |
#from(slug) ⇒ Object
CRUD handle for a collection.
38 39 40 |
# File 'lib/backlex/client.rb', line 38 def from(slug) Collection.new(self, slug) end |
#get_raw(path) ⇒ Object
Raw byte download (storage). Returns the response body string.
86 87 88 89 90 91 92 93 94 95 |
# File 'lib/backlex/client.rb', line 86 def get_raw(path) uri = URI(@url + path) req = Net::HTTP::Get.new(uri) auth_header(req) res = send_request(uri, req) code = res.code.to_i raise Backlex::Error.new(code, "UNKNOWN", "HTTP #{code}") if code < 200 || code >= 300 res.body end |
#put_raw(path, body, content_type) ⇒ Object
Raw-body upload (storage). Returns the parsed JSON response.
72 73 74 75 76 77 78 79 80 81 82 83 |
# File 'lib/backlex/client.rb', line 72 def put_raw(path, body, content_type) uri = URI(@url + path) req = Net::HTTP::Put.new(uri) req["Content-Type"] = content_type if content_type req.body = body auth_header(req) res = send_request(uri, req) code = res.code.to_i raise Backlex::Error.from(code, res.body) if code < 200 || code >= 300 res.body.nil? || res.body.empty? ? nil : JSON.parse(res.body) end |
#request(method, path, body = nil) ⇒ Object
Raw escape hatch — issues a JSON request with auth headers applied.
57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/backlex/client.rb', line 57 def request(method, path, body = nil) uri = URI(@url + path) req = build_request(method, uri) req["Content-Type"] = "application/json" req.body = JSON.generate(body) unless body.nil? auth_header(req) res = send_request(uri, req) code = res.code.to_i raise Backlex::Error.from(code, res.body) if code < 200 || code >= 300 return nil if code == 204 || res.body.nil? || res.body.empty? JSON.parse(res.body) end |
#storage ⇒ Object
46 47 48 |
# File 'lib/backlex/client.rb', line 46 def storage @storage ||= Storage.new(self) end |
#subscribe(channel, on_event, on_error = nil) ⇒ Object
Subscribe to a realtime channel (e.g. "items:posts"). Returns a Subscription; #close unsubscribes. on_error may be nil.
52 53 54 |
# File 'lib/backlex/client.rb', line 52 def subscribe(channel, on_event, on_error = nil) Subscription.new(self, "#{@url}/api/realtime/#{channel}/subscribe", on_event, on_error) end |