Hooks¶
Falcon supports before and after hooks. You install a hook simply by applying one of the decorators below, either to an individual responder or to an entire resource.
For example, consider this hook that validates a POST request for an image resource:
def validate_image_type(req, resp, resource, params):
if req.content_type not in ALLOWED_IMAGE_TYPES:
msg = 'Image type not allowed. Must be PNG, JPEG, or GIF'
raise falcon.HTTPBadRequest(title='Bad request', description=msg)
You would attach this hook to an on_post
responder like so:
@falcon.before(validate_image_type)
def on_post(self, req, resp):
pass
Or, suppose you had a hook that you would like to apply to all responders for a given resource. In that case, you would simply decorate the resource class:
@falcon.before(extract_project_id)
class Message:
def on_post(self, req, resp, project_id):
pass
def on_get(self, req, resp, project_id):
pass
Note
When decorating an entire resource class, all method names that resemble
responders, including suffixed (see also add_route()
)
ones, are decorated. If, for instance, a method is called on_get_items
,
but it is not meant for handling GET
requests under a route with the
suffix items
, the easiest workaround for preventing the hook function
from being applied to the method is renaming it not to clash with the
responder pattern.
Note also that you can pass additional arguments to your hook function as needed:
def validate_image_type(req, resp, resource, params, allowed_types):
if req.content_type not in allowed_types:
msg = 'Image type not allowed.'
raise falcon.HTTPBadRequest(title='Bad request', description=msg)
@falcon.before(validate_image_type, ['image/png'])
def on_post(self, req, resp):
pass
Falcon supports using any callable as a hook. This allows for using a class instead of a function:
class Authorize:
def __init__(self, roles):
self._roles = roles
def __call__(self, req, resp, resource, params):
pass
@falcon.before(Authorize(['admin']))
def on_post(self, req, resp):
pass
Falcon middleware components can also be used to insert logic before and after requests. However, unlike hooks, middleware components are triggered globally for all requests.
Tip
In order to pass data from a hook function to a resource function
use the req.context
and resp.context
objects. These context objects
are intended to hold request and response data specific to your app as it
passes through the framework.
Before Hooks¶
- falcon.before(action, *args, is_async=False, **kwargs)[source]¶
Execute the given action function before the responder.
The params argument that is passed to the hook contains only the fields from the URI template path; it does not include query string values.
Hooks may inject extra params as needed. For example:
def do_something(req, resp, resource, params): try: params['id'] = int(params['id']) except ValueError: raise falcon.HTTPBadRequest(title='Invalid ID', description='ID was not valid.') params['answer'] = 42
- Parameters
action (callable) – A function of the form
func(req, resp, resource, params)
, where resource is a reference to the resource class instance associated with the request and params is a dict of URI template field names, if any, that will be passed into the resource responder as kwargs.*args – Any additional arguments will be passed to action in the order given, immediately following the req, resp, resource, and params arguments.
- Keyword Arguments
is_async (bool) –
Set to
True
for ASGI apps to provide a hint that the decorated responder is a coroutine function (i.e., that it is defined withasync def
) or that it returns an awaitable coroutine object.Normally, when the function source is declared using
async def
, the resulting function object is flagged to indicate it returns a coroutine when invoked, and this can be automatically detected. However, it is possible to use a regular function to return an awaitable coroutine object, in which case a hint is required to let the framework know what to expect. Also, a hint is always required when using a cythonized coroutine function, since Cython does not flag them in a way that can be detected in advance, even when the function is declared usingasync def
.**kwargs – Any additional keyword arguments will be passed through to action.
After Hooks¶
- falcon.after(action, *args, is_async=False, **kwargs)[source]¶
Execute the given action function after the responder.
- Parameters
action (callable) – A function of the form
func(req, resp, resource)
, where resource is a reference to the resource class instance associated with the request*args – Any additional arguments will be passed to action in the order given, immediately following the req, resp and resource arguments.
- Keyword Arguments
is_async (bool) –
Set to
True
for ASGI apps to provide a hint that the decorated responder is a coroutine function (i.e., that it is defined withasync def
) or that it returns an awaitable coroutine object.Normally, when the function source is declared using
async def
, the resulting function object is flagged to indicate it returns a coroutine when invoked, and this can be automatically detected. However, it is possible to use a regular function to return an awaitable coroutine object, in which case a hint is required to let the framework know what to expect. Also, a hint is always required when using a cythonized coroutine function, since Cython does not flag them in a way that can be detected in advance, even when the function is declared usingasync def
.**kwargs – Any additional keyword arguments will be passed through to action.