4. Hooks
Overview
Hooks
are a mechanism whereby application developers can add arbitrary behavior to flag evaluation. They operate similarly to middleware in many web frameworks.
Hooks add their logic at any of four specific stages of flag evaluation:
before
, immediately before flag evaluationafter
, immediately after successful flag evaluationerror
, immediately after an unsuccessful flag evaluationfinally
, unconditionally after flag evaluation
Hooks can be configured to run globally (impacting all flag evaluations), per client, or per flag evaluation invocation. Some example use cases for a hook include adding additional data to the evaluation context, performing validation on the received flag value, providing data to telemetric tools, and logging errors.
Definitions
Hook: Application author/integrator-supplied logic that is called by the OpenFeature framework at a specific stage.
Stage: An explicit portion of the flag evaluation lifecycle. e.g. before
being "before" the resolution is run.
Invocation: A single call to evaluate a flag. client.getBooleanValue(..)
is an invocation.
API: The global API singleton.
4.1. Hook context
Hook context exists to provide hooks with information about the invocation.
Requirement 4.1.1
Hook context MUST provide: the
flag key
,flag value type
,evaluation context
, and thedefault value
.
Requirement 4.1.2
The
hook context
SHOULD provide access to theclient metadata
and theprovider metadata
fields.
Requirement 4.1.3
The
flag key
,flag type
, anddefault value
properties MUST be immutable. If the language does not support immutability, the hook MUST NOT modify these properties.
Condition 4.1.4
The implementation uses the dynamic-context paradigm.
Conditional Requirement 4.1.4.1
The evaluation context MUST be mutable only within the
before
hook.
4.2. Hook Hints
Requirement 4.2.1
hook hints
MUST be a structure supports definition of arbitrary properties, with keys of typestring
, and values of typeboolean | string | number | datetime | structure
.
Condition 4.2.2
The implementation language supports a mechanism for marking data as immutable.
Conditional Requirement 4.2.2.1
Condition:
Hook hints
MUST be immutable.
Conditional Requirement 4.2.2.2
Condition: The client
metadata
field in thehook context
MUST be immutable.
Conditional Requirement 4.2.2.3
Condition: The provider
metadata
field in thehook context
MUST be immutable.
4.3. Hook creation and parameters
Requirement 4.3.1
Hooks MUST specify at least one stage.
Condition 4.3.2
The implementation uses the dynamic-context paradigm.
Conditional Requirement 4.3.2.1
The
before
stage MUST run before flag resolution occurs. It accepts ahook context
(required) andhook hints
(optional) as parameters and returns either anevaluation context
or nothing.
EvaluationContext | void before(HookContext hookContext, HookHints hints);
Condition 4.3.3
The implementation uses the static-context paradigm.
Conditional Requirement 4.3.3.1
The
before
stage MUST run before flag resolution occurs. It accepts ahook context
(required) andhook hints
(optional) as parameters. It has no return value.
void before(HookContext hookContext, HookHints hints);
Requirement 4.3.4
Any
evaluation context
returned from abefore
hook MUST be passed to subsequentbefore
hooks (viaHookContext
).
Requirement 4.3.5
When
before
hooks have finished executing, any resultingevaluation context
MUST be merged with the existingevaluation context
.
Evaluation context merge order is defined in Context levels and merging.
Requirement 4.3.6
The
after
stage MUST run after flag resolution occurs. It accepts ahook context
(required),evaluation details
(required) andhook hints
(optional). It has no return value.
Requirement 4.3.7
The
error
hook MUST run when errors are encountered in thebefore
stage, theafter
stage or during flag resolution. It acceptshook context
(required),exception
representing what went wrong (required), andhook hints
(optional). It has no return value.
Requirement 4.3.8
The
finally
hook MUST run after thebefore
,after
, anderror
stages. It accepts ahook context
(required),evaluation details
(required) andhook hints
(optional). It has no return value.
The evaluation details passed to the finally
stage matches the evaluation details returned to the application author.
Condition 4.3.9
finally
is a reserved word in the language.
Conditional Requirement 4.3.9.1
Instead of
finally
,finallyAfter
SHOULD be used.
4.4. Hook registration & ordering
Requirement 4.4.1
The API, Client, Provider, and invocation MUST have a method for registering hooks.
OpenFeature.addHooks(new Hook1());
//...
Client client = OpenFeature.getClient();
client.addHooks(new Hook2());
`
//...
client.getValue('my-flag', 'defaultValue', new Hook3());
Requirement 4.4.2
Hooks MUST be evaluated in the following order:
- before: API, Client, Invocation, Provider
- after: Provider, Invocation, Client, API
- error (if applicable): Provider, Invocation, Client, API
- finally: Provider, Invocation, Client, API
Requirement 4.4.3
If a
finally
hook abnormally terminates, evaluation MUST proceed, including the execution of any remainingfinally
hooks.
In languages with try/catch semantics, this means that exceptions thrown in finally
hooks should be caught and not propagated up the call stack.
Requirement 4.4.4
If an
error
hook abnormally terminates, evaluation MUST proceed, including the execution of any remainingerror
hooks.
In languages with try/catch semantics, this means that exceptions thrown in error
hooks should be caught, and not propagated up the call stack.
Requirement 4.4.5
If an error occurs in the
before
orafter
hooks, theerror
hooks MUST be invoked.
Requirement 4.4.6
If an error occurs during the evaluation of
before
orafter
hooks, any remaining hooks in thebefore
orafter
stages MUST NOT be invoked.
Requirement 4.4.7
If an error occurs in the
before
hooks, the default value MUST be returned.
Before hooks can impact evaluation by various means, such as mutating the evaluation context
. Therefore, an error in the before
hooks is considered abnormal execution, and the default should be returned.
Flag evaluation options
Usage might look something like:
val = client.get_boolean_value('my-key', False, evaluation_options={
'hooks': new MyHook(),
'hook_hints': {'side-item': 'onion rings'}
})
Requirement 4.5.1
Flag evaluation options
MAY containhook hints
, a map of data to be provided to hook invocations.
Requirement 4.5.2
hook hints
MUST be passed to each hook.
Requirement 4.5.3
The hook MUST NOT alter the
hook hints
structure.