Skip to main content
Routes handle HTTP requests. Feather discovers modules in routes/api/ and routes/pages/ automatically.
routes/api/users.py

Prefixes

Keep routes thin

Parse the request, call a service, return a response. A handler doing work that belongs in a service is reported by feather check as the fat-route warning.

Services

Where business logic goes, with transactions handled for you.

Exceptions

Raise a typed exception and it becomes the right JSON response.

Redirecting after an action

Most actions end by sending the browser somewhere with a message. redirect_with_toast does both, and works for an htmx request and a plain form post alike: htmx gets an HX-Redirect, a normal request a 302, and the toast shows on the page that loads.
For an htmx-only redirect with no message, htmx_redirect(url) sends just the header.

Auth decorators

Every route should carry one, or declare itself public. A route with no auth decorator is reported as the unprotected-route warning. A deliberately public one carries a # feather: public comment in its module. See Authentication for the full decorator set.

Template filters, globals and error pages

Register app-wide helpers on the page blueprint, in a module under routes/pages/, not in app.py:
routes/pages/template_helpers.py
The test suite builds its app from TestingConfig and never imports app.py, so anything registered there exists when you run the app and is missing in every test. The blueprint’s app_* hooks reach every app Feather builds from the project.
Discovery skips any module whose name starts with an underscore. routes/pages/_helpers.py is never imported and its decorators never run, so name it template_helpers.py.

Seeing what is registered

Generate CRUD scaffolding with: