Interceptors (Hooks & Middlewares)¶
Heaven uses a centralized interceptors system to handle middleware. Instead of "wrapping" applications in layers of opaque middleware, you register interceptors i.e. hooks that run .BEFORE or .AFTER a request.
The Hook Lifecycle¶
- Request arrives.
- Match Route: The router finds the handler for the URL.
- Run BEFORE Hooks: Any hooks matching the URL are run.
- Run Handler: The actual route handler is executed.
- Run AFTER Hooks: Any hooks matching the URL are run.
- Response sent.
Registering Hooks¶
Note
Hooks are run in the order they are registered.
Hooks are registered with a glob-like URL pattern.
# Run on EVERY request
app.BEFORE('/*', global_auth_check) # run me 1st
# Run only on /api routes
app.BEFORE('/api/*', rate_limiter) # run me 2nd
# Run on a specific route
app.AFTER('/users/:id', log_access) # run me 3rd
Execution Order & Mounting¶
- FIFO: Hooks are executed in the exact order they are registered.
- Mounting: When you mount a sub-application (
child) onto aparentapp, the order is preserved nicely:- BEFORE Hooks: Parent hooks run first, then Child hooks. (Guard Pattern: Global Auth -> Specific Logic).
- AFTER Hooks: Child hooks run first, then Parent hooks. (Unwinding: Specific Cleanup -> Global Cleanup).
The Hook Signature¶
Hooks share the exact same signature as route handlers.
async def my_hook(req, res, ctx):
# You can modify the request
req.headers['x-checked'] = 'true'
# You can modify the context
ctx.user = await get_user(req)
# You can ABORT the request (shortcuts the pipeline)
if not ctx.user:
res.status = 401
res.abort("Unauthorized")
CORS (Cross-Origin Resource Sharing)¶
CORS is a common requirement, so Heaven includes a dedicated helper that registers the necessary hooks for you.
Simple¶
# Allow everything (wildcard)
app.cors()
configured¶
app.cors(
origin='https://myapp.com',
methods=['GET', 'POST'],
headers=['Authorization', 'Content-Type'],
max_age=3600 # or maxAge, MAX_AGE etc.
)
Note
app.cors is smart enough to handle different casing styles for arguments (e.g. max_age, maxAge, MAX_AGE all work).
Note that app.cors() is just a wrapper that registers a .BEFORE('/*') hook that handles the OPTIONS method and sets the correct Access-Control-* headers.
Next: You know how to intercept, how about API Docs? On to Schemas.