falconry / falcon

The no-magic web data plane API and microservices framework for Python developers, with a focus on reliability, correctness, and performance at scale.
https://falcon.readthedocs.io/en/stable/
Apache License 2.0
9.51k stars 937 forks source link

Hook after params attribute is missing #1954

Closed bronte2k7 closed 3 years ago

bronte2k7 commented 3 years ago

Hi

def do_before(req, resp, resource, params):
    # here params is available

def do_after(req, resp, resource, params):
    # here params is not available

How can I access the params?

vytas7 commented 3 years ago

Hi @bronte2k7 ! Currently, the framework is designed in a way that "after" hooks do not have access to params, and the signature they should follow is func(req, resp, resource) (plus any additional args/kwargs you can pass via falcon.after).

I see though that documentation for the *args parameter in falcon.after does mention params, but that's most likely a copy-paste mistake that we'll try to rectify.

The idea of after hooks is that they are thought to be used for post-processing the response, where access to params is seldom needed. See also the process_response middleware method.

However, if you do happen to need access to params, or pass any other custom data along the request-response cycle, you can also use req.context and/or resp.context for that purpose.

For instance:

import falcon

def do_before(req, resp, resource, params):
    if params.get('vegetable') == 'cucumber':
        colour = 'green'
    elif params.get('vegetable') == 'tomato':
        colour = 'red'
    else:
        colour = None

    resp.context.colour = params['colour'] = colour

def do_after(req, resp, resource):
    if resp.context.colour:
        resp.set_header('X-Colour', resp.context.colour)

class Vegetables:
    @falcon.before(do_before)
    @falcon.after(do_after)
    def on_get(self, req, resp, vegetable, colour):
        resp.media = {'vegetable': vegetable, 'colour': colour}

app = falcon.App()
app.add_route('/vegetables/{vegetable}', Vegetables())

See also: How can I pass data from a hook to a responder, and between hooks?

bronte2k7 commented 3 years ago

Thanks for the detailed answer. Using context is a great idea)))