Class: Fluence::Gateway::Client

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
Singleton
Defined in:
lib/fluence/gateway/http_client.rb

Overview

Singleton HTTP client for the Fluence API gateway.

Handles OAuth2 client_credentials authentication transparently: the service token is fetched on the first request and refreshed on demand. End-user Bearer tokens can be forwarded per call or for an entire block, and the target service can be encoded into the URL via the service: kwarg or the #with_service block helper.

All HTTP verbs (get, post, put, patch, delete) are defined on both the singleton instance and the class (class-level delegation), so callers never need to reference .instance explicitly.

Thread-safety: the OAuth2::Client cache and token refresh are guarded by a reentrant Monitor, which allows access_token_for (already inside the lock) to call oauth_client_for (which also takes the lock) without deadlocking. Per-block scopes (#with_user_token, #with_service, #with_tenant) are stored in Thread.current and restored when the block exits, including on exception.

Examples:

Configure once, call anywhere

Fluence::Gateway.configure do |c|
  c.client_id     = ENV.fetch('APPCENTER_CLIENT_ID')
  c.client_secret = ENV.fetch('APPCENTER_CLIENT_SECRET')
end

Fluence::Gateway::Client.get('/api/v1/valuations', service: :base_valeur)
# → GET /backend/base-valeur/api/v1/valuations

Forward the end-user token for a whole block

Fluence::Gateway::Client.with_user_token(current_user.token) do
  Fluence::Gateway::Client.get('/api/v1/me', service: :base_valeur)
end

Scope multiple calls to the same service

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

See Also:

Class Method Summary collapse

Class Method Details

.delete(path, user_token: nil, service: nil, tenant: nil, raw: false, **opts) ⇒ Hash, ...

Performs a DELETE request on the gateway.

Parameters:

  • path (String)

    the resource path (leading slash optional)

  • user_token (String, nil) (defaults to: nil)

    optional end-user Bearer token to forward

  • service (Symbol, String, nil) (defaults to: nil)

    optional target service (see .get)

  • tenant (Symbol, String, nil) (defaults to: nil)

    optional tenant (see .get)

  • raw (Boolean) (defaults to: false)

    when true, returns the underlying OAuth2::Response instead of its parsed body (useful to access #headers, #status)

  • opts (Hash)

    extra options forwarded to OAuth2::AccessToken#delete

Returns:

  • (Hash, Array, String, OAuth2::Response)

    parsed JSON for JSON content types, raw .body String for anything else (PDF, CSV, …), or the full OAuth2::Response when raw: true

Raises:

.get(path, user_token: nil, service: nil, tenant: nil, raw: false, **opts) ⇒ Hash, ...

Performs a GET request on the gateway.

Parameters:

  • path (String)

    the resource path (leading slash optional)

  • user_token (String, nil) (defaults to: nil)

    optional end-user Bearer token to forward instead of the service client_credentials token

  • service (Symbol, String, nil) (defaults to: nil)

    optional target service. When set, the path is rewritten as /backend/<service>/<path>. Symbols have their underscores converted to dashes (:base_valeurbase-valeur); strings are used as-is. Overrides any with_service block in scope.

  • tenant (Symbol, String, nil) (defaults to: nil)

    optional tenant name. When set, the call is routed through that tenant's gateway/credentials. Accepts user-declared tenants from config.tenants and the gem's built-in tenants (e.g. :mosaic). Overrides any with_tenant block in scope; pass tenant: nil explicitly to force the global default tenant.

  • raw (Boolean) (defaults to: false)

    when true, returns the underlying OAuth2::Response instead of its parsed body (useful to access #headers, #status)

  • opts (Hash)

    extra options forwarded to OAuth2::AccessToken#get

Returns:

  • (Hash, Array, String, OAuth2::Response)

    parsed JSON for JSON content types, raw .body String for anything else (PDF, CSV, …), or the full OAuth2::Response when raw: true

Raises:

.patch(path, user_token: nil, service: nil, tenant: nil, body: nil, raw: false, **opts) ⇒ Hash, ...

Performs a PATCH request on the gateway.

Parameters:

  • path (String)

    the resource path (leading slash optional)

  • user_token (String, nil) (defaults to: nil)

    optional end-user Bearer token to forward

  • service (Symbol, String, nil) (defaults to: nil)

    optional target service (see .get)

  • tenant (Symbol, String, nil) (defaults to: nil)

    optional tenant (see .get)

  • body (Hash) (defaults to: nil)

    the request body (serialized as JSON)

  • raw (Boolean) (defaults to: false)

    when true, returns the underlying OAuth2::Response instead of its parsed body (useful to access #headers, #status)

  • opts (Hash)

    extra options forwarded to OAuth2::AccessToken#patch

Returns:

  • (Hash, Array, String, OAuth2::Response)

    parsed JSON for JSON content types, raw .body String for anything else (PDF, CSV, …), or the full OAuth2::Response when raw: true

Raises:

.post(path, user_token: nil, service: nil, tenant: nil, body: nil, raw: false, **opts) ⇒ Hash, ...

Performs a POST request on the gateway.

Parameters:

  • path (String)

    the resource path (leading slash optional)

  • user_token (String, nil) (defaults to: nil)

    optional end-user Bearer token to forward

  • service (Symbol, String, nil) (defaults to: nil)

    optional target service (see .get)

  • tenant (Symbol, String, nil) (defaults to: nil)

    optional tenant (see .get)

  • body (Hash) (defaults to: nil)

    the request body (serialized as JSON)

  • raw (Boolean) (defaults to: false)

    when true, returns the underlying OAuth2::Response instead of its parsed body (useful to access #headers, #status)

  • opts (Hash)

    extra options forwarded to OAuth2::AccessToken#post

Returns:

  • (Hash, Array, String, OAuth2::Response)

    parsed JSON for JSON content types, raw .body String for anything else (PDF, CSV, …), or the full OAuth2::Response when raw: true

Raises:

.put(path, user_token: nil, service: nil, tenant: nil, body: nil, raw: false, **opts) ⇒ Hash, ...

Performs a PUT request on the gateway.

Parameters:

  • path (String)

    the resource path (leading slash optional)

  • user_token (String, nil) (defaults to: nil)

    optional end-user Bearer token to forward

  • service (Symbol, String, nil) (defaults to: nil)

    optional target service (see .get)

  • tenant (Symbol, String, nil) (defaults to: nil)

    optional tenant (see .get)

  • body (Hash) (defaults to: nil)

    the request body (serialized as JSON)

  • raw (Boolean) (defaults to: false)

    when true, returns the underlying OAuth2::Response instead of its parsed body (useful to access #headers, #status)

  • opts (Hash)

    extra options forwarded to OAuth2::AccessToken#put

Returns:

  • (Hash, Array, String, OAuth2::Response)

    parsed JSON for JSON content types, raw .body String for anything else (PDF, CSV, …), or the full OAuth2::Response when raw: true

Raises:

.with_service(service) { ... } ⇒ Object

Scopes a block of gateway calls to the given backend service.

Paths issued inside the block are automatically prefixed with /backend/<service>/. When service is a Symbol, underscores are converted to dashes (:base_valeurbase-valeur); when it is a String, it is used as-is. The scope is stored in Thread.current and restored when the block exits, including on exception. A service: kwarg on a call site always wins over the value set here.

Examples:

Avoid repeating service: on every call

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

Parameters:

  • service (Symbol, String)

    the target service name

Yields:

  • block in which gateway calls are scoped to service

Returns:

  • (Object)

    the block's return value

.with_tenant(tenant) { ... } ⇒ Object

Scopes a block of gateway calls to the given tenant.

Calls issued inside the block are routed through the tenant's gateway/credentials (resolved via Fluence::Gateway::Configuration::Settings#tenant_config). Accepts user-declared tenants from config.tenants and the gem's built-in tenants (e.g. :mosaic). The name is validated eagerly — an unknown tenant raises UnknownTenantError before the block runs. A tenant: kwarg on a call site always wins over the value set here; tenant: nil explicitly forces the global default tenant. The scope is stored in Thread.current and restored when the block exits, including on exception.

Examples:

Route a flow through the Mosaic tenant

Fluence::Gateway::Client.with_tenant(:mosaic) do
  Fluence::Gateway::Client.get('/api/v1/me')
end

Parameters:

  • tenant (Symbol, String, nil)

    the tenant name (or nil for the global default)

Yields:

  • block in which gateway calls are routed through tenant

Returns:

  • (Object)

    the block's return value

Raises:

.with_user_token(token) { ... } ⇒ Object

Scopes a block of gateway calls to forward token as the end-user Bearer instead of the cached service token.

The token is stored in Thread.current so it survives nested calls on the same thread but does not leak to other threads. Any explicit user_token: kwarg on a call site always wins over the value set here. The previous value (if any) is restored when the block exits, including on exception.

Examples:

Forward the current user's token for all calls in a block

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

Parameters:

  • token (String)

    the end-user Bearer token

Yields:

  • block in which gateway calls forward token

Returns:

  • (Object)

    the block's return value