Skip to content

Routing

FastApp routes mirror the Laravel style you might know from PHP frameworks. Define declarative Route objects, then register them against your Quart application with register_routes. A typical project keeps these definitions in app/http_files/routes/api.py to keep HTTP wiring in one place.

Declaring routes

Import the Route contract and compose a list of routes. Each HTTP verb has a convenience constructor:

  • Route.get(path, handler, middlewares=None)
  • Route.post(...)
  • Route.put(...)
  • Route.patch(...)
  • Route.delete(...)
  • Route.options(...)
  • Route.head(...)

Handlers can be callables or coroutine functions. Middlewares accept either middleware classes implementing fast_app.contracts.middleware.Middleware, instances, or simple callables that wrap the handler.

from fast_app import Route, ThrottleMiddleware
from app.http_files.controllers import ping_controller

routes = [
    Route.get("/ping", ping_controller.show),
    Route.post("/signup", auth_controller.register, [ThrottleMiddleware(limit=10, window_seconds=60)]),
]

Route groups

Use Route.group() to share prefixes or middleware across nested routes. Groups can be nested arbitrarily, and you can mix prefix and middlewares arguments:

from app.http_files.middlewares import AuthMiddleware, BusinessMiddleware

routes = [
    Route.group("/auth", routes=[
        Route.post("/dispatch", auth_controller.dispatch),
        Route.post("/exchange", auth_controller.exchange),
        Route.delete("/", auth_controller.logout, [AuthMiddleware]),
    ]),
    Route.group(
        middlewares=[AuthMiddleware, BusinessMiddleware],
        routes=[
            Route.get("/chat/history", chat_controller.get_history),
            # ... more nested routes
        ],
    ),
]

When you call Route.group(prefix="/reports", routes=[...]), all nested paths inherit the /reports prefix. Middleware declared on the group runs before route-specific middleware, and global middlewares such as HandleExceptionsMiddleware and ResourceResponseMiddleware are injected automatically when you register the routes.

Resource routes

Route.resource(path, controller) generates a small CRUD route group. The controller must expose the following callables:

  • index — list resources (GET path/)
  • show — fetch a resource (GET path/<id>)
  • store — create a resource (POST path/)
  • update — update a resource (PATCH path/<id>)
  • destroy — delete a resource (DELETE path/<id>)

Method names can be overridden by passing controller_methods. For example:

Route.resource(
    "/lead",
    lead_controller,
    controller_methods={"update": "patch", "destroy": "soft_delete"},
)

If you prefer an alternate path parameter (defaults to <lead_id> based on the slug), supply parameter="<slug>".

Because Route.resource returns a group, you can nest additional routes alongside it:

routes = [
    Route.resource("/order", order_controller),
    Route.group("/order/<order_id>", routes=[
        Route.post("/attachment", order_controller.upload_attachments),
        Route.delete("/attachment/<file_id>", order_controller.remove_attachment),
    ]),
]

Registering routes with Quart

Once your list is ready, register it with the Quart app. register_routes flattens groups, applies middleware ordering, and calls app.add_url_rule for every definition.

from quart import Quart
from fast_app.utils.routing_utils import register_routes
from app.http_files.routes.api import routes

app = Quart(__name__)
register_routes(app, routes)

if __name__ == "__main__":
    app.run()

register_routes injects global middlewares in the following order: HandleExceptionsMiddleware, ModelBindingMiddleware, SchemaValidationMiddleware, user-specified middlewares, and finally ResourceResponseMiddleware. This ensures consistent request handling regardless of where your routes live.

Keep HTTP routes close to controllers and schemas. A common layout:

app/
  http_files/
    routes/
      api.py          # Route list exported as `routes`
    controllers/
      auth_controller.py
      lead_controller.py
    middlewares/
      auth_middleware.py

Import routes from that module inside your Quart entry point (e.g., app/modules/asgi/app.py) to keep the route table declarative and discoverable.