Horje
Python Falcon - Hooks

In Falcon, hooks are type of callbacks that are defined by the user and are executed before or after a responder method in a particular resource class to process client request. They are useful in as much as they allow a client to add or overwrite request processing functionality at certain predefined stages.

Understanding Hooks in Python Falcon

Falcon offers two types of hooks:

1. Before Hooks

Executed before the corresponding responder method is invoked. They are ideal for tasks such as:

  • Authentication and authorization
  • Input validation and pre-processing
  • Security checks

2. After Hooks

They should be called after the responder method is done with the request processing. They are typically used for:

  • Logging
  • Post-processing data
  • Sending notifications

Using Hooks

Falcon provides two decorators, @falcon.before and @falcon.after, for hanging callbacks on responder methods, or indeed on whole classes of resources. The arguments passed to hook functions include:

req (falcon. Request): The current HTTP request object with each of the typically included objects in the request being defined as a property of the HTTP request object.

resp (falcon. Response): This is the current HTTP response instance used for the current request.

resource (object): The resource class instance of the particular request that the customer or the client wants to access.

params (dict): This is the portion of the URI template either consisting of field names and corresponding values when they are present.

Example: Authentication Hook

Let’s create a simple example where we use a before hook to check for an authentication token in the request headers.

Step 1: Setting Up Falcon

Firstly, install Falcon if you haven’t installed already:

pip install falcon

Step 2: Writing the Hook

Create a file named app.py and start by importing the necessary modules and writing the hook function:

Python
#app.py
import falcon

# Define the authentication hook
def auth_hook(req, resp, resource, params):
    token = req.get_header('Authorization')
    if token != 'secret-token':
        raise falcon.HTTPUnauthorized('Authentication required',
                                      'Please provide a valid token.')
  • auth_hook is a function that checks for an Authorization header in the request.
  • If the token is not secret-token, it raises an HTTPUnauthorized exception, which results in a 401 Unauthorized response.

Step 3: Creating a Resource

Next, define a resource where the hook will be applied:

Python
#app.py

# Define the resource with request handlers
class ResourceWithAuth:
    @falcon.before(auth_hook)
    def on_get(self, req, resp):
        resp.media = {'message': 'You are authenticated!'}

    @falcon.before(auth_hook)
    def on_post(self, req, resp):
        resp.media = {'message': 'Data received!'}

ResourceWithAuth is a resource class with two methods:

  • on_get: Handles GET requests and responds with a JSON message.
  • on_post: Handles POST requests and responds with a JSON message.


Step 4: Setting Up the API

Set up the Falcon API and add the route:

Python
#app.py continue...

# Set up the Falcon API and add the route
app = falcon.App()
app.add_route('/secure', ResourceWithAuth())

# Run the application using the built-in WSGI server
if __name__ == '__main__':
    from wsgiref.simple_server import make_server
    with make_server('', 8000, app) as httpd:
        print('Serving on port 8000...')
        httpd.serve_forever()

Running the Application

Run your Falcon application, using:

python app.py

You should see the output indicating that the server is running:

server

output

Testing the Hook

Let’s test our before hook using curl:

Without Token

curl -i http://localhost:8000/secure

Output:

woo

Output – Without token

With Token

curl -i -H "Authorization: secret-token" http://localhost:8000/secure

Output:

wt

Output – With Token

Example: Logging (After Hooks)

After hooks are defined similarly but are used to modify the response:

Setting Up Logging:

Python
import falcon
import logging 

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
  • This sets up basic logging configuration with the log level set to INFO.
  • logger is an instance of a logger to log messages.

Defining the After Hook:

Python
def add_custom_header(req, resp, resource, req_succeeded):
    logger.info(f"Processing {req.method} request for {req.path}")
    resp.set_header('X-Custom-Header', 'CustomValue')
  • add_custom_header is a function that constructs a log message using the request method, the requested URI, and the response status.
  • The log message is then logged using logger.info.

Creating the Resource with Request Handlers:

Python
class ResourceWithAfterHook:
    @falcon.after(add_custom_header)
    def on_get(self, req, resp):
        logger.info("Handling GET request")
        resp.media = {'message': 'Response with a custom header!'}

    @falcon.after(add_custom_header)
    def on_post(self, req, resp):
        logger.info("Handling POST request")
        resp.media = {'message': 'Data received with a custom header!'}

ResourceWithAfterHook is a resource class with two methods:

  • on_get: Handles GET requests and responds with a JSON message.
  • on_post: Handles POST requests and responds with a JSON message.

The @falcon.after(add_custom_header) decorator applies the add_custom_header hook to both methods.

Setting Up the Falcon API and Adding the Route:

Python
app = falcon.App()
app.add_route('/custom', ResourceWithAfterHook())


Running the Application:

Python
if __name__ == '__main__':
    from wsgiref.simple_server import make_server
    with make_server('', 8000, app) as httpd:
        print('Serving on port 8000...')
        httpd.serve_forever()

This block of code checks if the script is being run directly.

It uses Python’s built-in WSGI server to serve the Falcon application on port 8000.

Testing the After Hook

To test the application and see the logging in action, you can use curl or any other HTTP client:

GET Request

curl -i http://localhost:8000/custom

POST Request

curl -i -X POST http://localhost:8000/custom

Advanced Hook Usage

Multiple Hooks

You can apply multiple hooks to a resource. Just chain them together using the Falcon decorators:

@falcon.before(auth_hook)
@falcon.before(another_hook)
class AnotherResource:
def on_get(self, req, resp):
resp.media = {'message': 'Multiple hooks applied!'}

By using Falcon hooks, we achieve clean separation of concerns, making our code more modular and easier to maintain.

Common Use Cases for Falcon Hooks

Authentication and Authorization:

Before hooks can be used to enforce some certain levels of authentication and authorization mechanisms by checking user credentials or tokens before granting the users access to the protected resources.

Logging:

When using hooks, after hooks in particular are usually followed by logging of the request and response details, including request method, URL, status, as well as execution time for diagnostics and control purposes.

Request Validation:

Before hooks can get a hold of incoming requests to check whether they meet specific criteria, it is essential to understand that all requests shall meet certain requirements like required parameters, data types, or format.

Response Manipulation:

Next paradigms allow hooks so that the actual content of the response, or the headers in which it is returned to the client, can be changed according to certain needs.

Caching:

Both before and after hooks can be used for caching strategies For the before hooks can check if it is there a cached response then it will immediately serve it , whereas after hooks can cache the response generated now to serve it in future similar requests.

Metrics Collection:

After hooks are discussed as a tool to capture metrics which are typically associated with API utilization for monitoring and optimization purposes such as the number of requests to the API, time taken to process requests, number of errors, etc.





Reffered: https://www.geeksforgeeks.org


Python

Related
How to Fix MXNet Error “Module 'numpy' Has No Attribute 'bool' in Python How to Fix MXNet Error “Module 'numpy' Has No Attribute 'bool' in Python
How to Create a Custom KeyboardInterrupt in Python How to Create a Custom KeyboardInterrupt in Python
Building a Background PDF Generation App Using Python Celery and Template Data Building a Background PDF Generation App Using Python Celery and Template Data
How to Fix "ValueError: dictionary update sequence element #0 has length X; 2 is required" in Python How to Fix "ValueError: dictionary update sequence element #0 has length X; 2 is required" in Python
How to Fix the "No module named 'mpl_toolkits.basemap'" Error in Python How to Fix the "No module named 'mpl_toolkits.basemap'" Error in Python

Type:
Geek
Category:
Coding
Sub Category:
Tutorial
Uploaded by:
Admin
Views:
19