Plugins¶
flarchitect supports a lightweight plugin system for observing and customising behaviour at well-defined hook points. Use plugins for cross-cutting concerns such as auditing, metrics, tenant scoping, or output shaping that shouldn’t live in route handlers.
Quick start¶
Implement a plugin by subclassing
flarchitect.plugins.PluginBase
:from flarchitect.plugins import PluginBase class AuditPlugin(PluginBase): def before_model_op(self, context): # e.g. attach actor/tenant to the payload data = context.get("deserialized_data") or {} if isinstance(data, dict): data = {**data, "actor": context.get("request_id")} return {"deserialized_data": data} def after_model_op(self, context, output): # e.g. emit an audit log print("AUDIT:", context.get("method"), context.get("model"), output)
Register your plugin via Flask config:
app.config["API_PLUGINS"] = [AuditPlugin()]
Hook reference¶
Stable hook signatures (kwargs may grow over time):
- request_started(request: flask.Request) -> None
Called at the beginning of each request.
- request_finished(request: flask.Request, response: flask.Response) -> flask.Response | None
Called after a response is created. Return a replacement Response to override.
- before_authenticate(context: dict) -> dict | None
Runs prior to authentication (for non-schema routes and schema routes alike). May return a dict of updates to merge into the context.
- after_authenticate(context: dict, success: bool, user: Any | None) -> None
Runs after authentication attempt.
- before_model_op(context: dict) -> dict | None
Runs before a CRUD action. Context includes keys such as
model
,method
,many
,id
,field
,join_model
,output_schema
and (for POST/PATCH)deserialized_data
. Return a dict to update the call-time kwargs (e.g., mutatedeserialized_data
).
- after_model_op(context: dict, output: Any) -> Any | None
Runs after a CRUD action. Return a value to replace the output before serialisation.
- spec_build_started(spec: apispec.APISpec) -> None
Called when building the OpenAPI specification.
- spec_build_completed(spec_dict: dict) -> dict | None
Called after the spec is converted to a dictionary. Return a dict to replace it.
Notes¶
Plugins are additive: multiple plugins can be installed; they are called in order.
Returning
None
means “no change”. Where supported, the first non-None
return value wins (e.g., response replacement).Existing callback config keys (e.g.,
API_SETUP_CALLBACK
) continue to work and compose with plugins.