Callbacks¶
Callbacks let you hook into the request lifecycle to run custom logic around database operations and responses. They can be declared globally in the Flask configuration or on individual SQLAlchemy models.
Callback types¶
flarchitect recognises a number of callback hooks that allow you to run custom logic at various stages of processing:
Global setup – runs before any model-specific processing.
GLOBAL_SETUP_CALLBACK(global:API_GLOBAL_SETUP_CALLBACK)Setup – runs before database operations. Useful for validation, logging or altering incoming data.
SETUP_CALLBACK(global:API_SETUP_CALLBACK)Filter – lets you adjust the SQLAlchemy query object before filtering and pagination are applied.
FILTER_CALLBACK(global:API_FILTER_CALLBACK)Add – called before a new object is committed to the database.
ADD_CALLBACK(global:API_ADD_CALLBACK)Update – invoked prior to persisting updates to an existing object.
UPDATE_CALLBACK(global:API_UPDATE_CALLBACK)Remove – executed before an object is deleted.
REMOVE_CALLBACK(global:API_REMOVE_CALLBACK)Return – runs after the database operation but before the response is returned. Ideal for adjusting the output or adding headers.
RETURN_CALLBACK(global:API_RETURN_CALLBACK)Dump – executes after Marshmallow serialisation allowing you to modify the dumped data.
DUMP_CALLBACK(global:API_DUMP_CALLBACK)Final – runs immediately before the response is sent to the client.
FINAL_CALLBACK(global:API_FINAL_CALLBACK)Error – triggered when an exception bubbles up; handle logging or notifications here.
ERROR_CALLBACK(global:API_ERROR_CALLBACK)
Configuration¶
Callbacks are referenced by the following configuration keys (global variants
use API_<KEY>):
GLOBAL_SETUP_CALLBACK/API_GLOBAL_SETUP_CALLBACKSETUP_CALLBACK/API_SETUP_CALLBACKFILTER_CALLBACK/API_FILTER_CALLBACKADD_CALLBACK/API_ADD_CALLBACKUPDATE_CALLBACK/API_UPDATE_CALLBACKREMOVE_CALLBACK/API_REMOVE_CALLBACKRETURN_CALLBACK/API_RETURN_CALLBACKDUMP_CALLBACK/API_DUMP_CALLBACKFINAL_CALLBACK/API_FINAL_CALLBACKERROR_CALLBACK/API_ERROR_CALLBACK
You can apply these keys in several places:
Global Flask config
Use
API_<KEY>to apply a callback to all endpoints.class Config: API_SETUP_CALLBACK = my_setup
HTTP method specific config
Override the global value for a specific method with
API_<METHOD>_<KEY>.class Config: API_GET_RETURN_CALLBACK = my_get_return
Model config
Set lowercase attributes on a model’s
Metaclass to apply callbacks to all endpoints for that model.class Author(db.Model): class Meta: setup_callback = my_setup
Model method config
Use
<method>_<key>on theMetaclass for the highest level of specificity.class Author(db.Model): class Meta: get_return_callback = my_get_return
Callback signatures¶
Setup, Global setup and filter¶
Setup-style callbacks should accept model and **kwargs and return the
modified kwargs:
def my_setup_callback(model, **kwargs):
# modify kwargs as needed
return kwargs
def my_filter_callback(query, model, params):
return query.filter(model.id > 0)
Add, update and remove¶
These callbacks receive the SQLAlchemy object instance and must return it:
def my_add_callback(obj, model):
obj.created_by = "system"
return obj
Return¶
Return callbacks receive model and output and must return a dictionary
containing the output key:
def my_return_callback(model, output, **kwargs):
return {"output": output}
Dump¶
Dump callbacks accept data and **kwargs and must return the data:
def my_dump_callback(data, **kwargs):
data["name"] = data["name"].upper()
return data
Final¶
Final callbacks receive the response dictionary before it is serialised:
def my_final_callback(data):
data["processed"] = True
return data
Error¶
Error callbacks receive the error message, status code and original value:
def my_error_callback(error, status_code, value):
log_exception(error)
Extending query parameters¶
Use ADDITIONAL_QUERY_PARAMS to document extra query parameters introduced in
a return callback. The value is a list of OpenAPI parameter objects.
class Config:
API_ADDITIONAL_QUERY_PARAMS = [{
"name": "log",
"in": "query",
"description": "Log call into the database",
"schema": {"type": "string"},
}]
class Author(db.Model):
class Meta:
get_additional_query_params = [{
"name": "log",
"in": "query",
"schema": {"type": "string"},
}]
Acceptable types¶
schema.type may be one of:
stringnumberintegerbooleanarrayobject
Acceptable formats¶
Common schema.format values include:
datedate-timepasswordbytebinaryemailphonepostal_codeuuidurihostnameipv4ipv6int32int64floatdouble
For comprehensive configuration details see Configuration.