fluence-gateway-client
Ruby client for service-to-service communication through the Fluence API Gateway. Handles OAuth2 client_credentials authentication transparently, builds backend URLs from a service name, and forwards end-user tokens when needed.
| Piece | Role |
|---|---|
Fluence::Gateway::Client |
Thread-safe singleton exposing get / post / put / patch / delete. Token refresh, path building, and end-user token forwarding live here. |
Fluence::Gateway.configure |
Configuration DSL (credentials, gateway and appcenter URLs, timeout). |
Fluence::Gateway::Client.with_service(:name) { } |
Thread-local scope that prefixes every path in the block with /backend/<service>/. |
Fluence::Gateway::Client.with_user_token(token) { } |
Thread-local scope that forwards an end-user Bearer token instead of the service token. |
Fluence::Gateway::Error and subclasses |
AuthenticationError (OAuth2 failure) and ConnectionError (gateway unreachable). |
Requires Ruby ≥ 3.2.
Installation
# Gemfile
source 'https://rubygems.pkg.github.com/fluence-eu' do
gem 'fluence-gateway-client'
end
bundle install
Configuration
Configure once at boot (Rails: config/initializers/fluence_gateway.rb).
Fluence::Gateway.configure do |c|
c.client_id = ENV.fetch('GATEWAY_CLIENT_ID')
c.client_secret = ENV.fetch('GATEWAY_CLIENT_SECRET')
end
| Setting | Type | Default | Behaviour |
|---|---|---|---|
client_id |
String | — | OAuth2 client_credentials identifier. Required. |
client_secret |
String | — | OAuth2 client_credentials secret. Required. |
gateway_url |
String | https://gateway.fluence-europe.cloud |
Base URL of the API gateway. |
appcenter_url |
String | https://appcenter.fluence-europe.cloud |
Base URL of the OAuth2 server (token endpoint). |
timeout |
Integer | 30 |
HTTP timeout, in seconds. |
Only client_id and client_secret have no defaults and must be set before the first call.
Usage
Calling a service
Pass the target service via the service: kwarg. The path is auto-prefixed with /backend/<service>/.
Fluence::Gateway::Client.get('/api/v1/valuations', service: :base_valeur)
# → GET /backend/base-valeur/api/v1/valuations
Fluence::Gateway::Client.post('/api/v1/valuations',
service: :base_valeur,
body: { asset_id: 42 })
Symbol service names have their underscores converted to dashes (:base_valeur → base-valeur). String service names are used as-is. When no service: is given, the path is sent to the gateway unchanged.
All verbs return parsed JSON (Hash or Array).
Scoping many calls to the same service
with_service stores the active service in the current thread, so every call inside the block inherits it:
Fluence::Gateway::Client.with_service(:base_valeur) do
Fluence::Gateway::Client.get('/api/v1/valuations')
Fluence::Gateway::Client.post('/api/v1/valuations', body: { asset_id: 42 })
end
A service: kwarg on the call site always overrides the block.
Forwarding an end-user token
When a request is made on behalf of an authenticated end-user, forward their Bearer so the gateway identifies the user instead of the calling service.
# Per call
Fluence::Gateway::Client.get('/api/v1/me',
service: :base_valeur,
user_token: current_user.access_token)
# Block — every call inside forwards the same token (thread-local)
Fluence::Gateway::Client.with_user_token(current_user.access_token) do
Fluence::Gateway::Client.get('/api/v1/me', service: :base_valeur)
Fluence::Gateway::Client.post('/api/v1/things',
service: :base_valeur,
body: { name: 'x' })
end
The service client_credentials token is cached separately: when a user_token: is present, it is wrapped in an ephemeral OAuth2::AccessToken for that request only. A user_token: kwarg always wins over a with_user_token block.
Error handling
begin
Fluence::Gateway::Client.get('/api/v1/me', service: :base_valeur)
rescue Fluence::Gateway::AuthenticationError => e
# OAuth2 credentials invalid or token endpoint returned 4xx/5xx — do not retry
rescue Fluence::Gateway::ConnectionError => e
# Gateway unreachable (timeout, connection refused) — safe to retry with backoff
rescue Fluence::Gateway::Error => e
# Anything else raised by the gem
end
Token lifecycle
The service client_credentials token is fetched lazily on the first call and cached in memory. When it expires, the client:
- Calls
refreshon the cached token if a refresh token is available; - Otherwise, requests a fresh token via
client_credentials.
Refresh is guarded by a Mutex, so concurrent callers share a single refresh round-trip.
Development
bin/setup
bundle exec rspec # tests
bundle exec rubocop # linting
bundle exec rake doc:build # generate YARD documentation in doc/
bundle exec rake doc:verify # check yardstick documentation-quality threshold
Contributing guidelines are in CONTRIBUTING.md.