Routers¶
Router helps split large FastHTTP applications into smaller reusable groups of routes.
It is useful when you want to:
- keep related requests together
- reuse route groups in multiple apps
- apply a shared
prefix,base_url,tags, ordependencies - build nested route trees
Basic Usage¶
from fasthttp import FastHTTP, Router
from fasthttp.response import Response
app = FastHTTP()
users = Router(base_url="https://api.example.com", prefix="/users", tags=["users"])
@users.get("/me")
async def get_me(resp: Response) -> dict:
return resp.json()
@users.get("/list")
async def get_users(resp: Response) -> dict:
return resp.json()
app.include_router(users)
This produces final request URLs:
https://api.example.com/users/mehttps://api.example.com/users/list
Router Parameters¶
You can configure a router with:
base_urlfor the host, for examplehttps://api.example.comprefixfor a shared path, for example/v1tagsinherited by all routes in the routerdependenciesinherited by all routes in the router
include_router()¶
Attach a router to the main app:
You can also override values when including it:
app.include_router(
router,
prefix="/public",
tags=["public"],
base_url="https://gateway.example.com",
)
The include-time values are applied before the router's own values.
Nested Routers¶
Routers can include other routers.
from fasthttp import FastHTTP, Router
from fasthttp.response import Response
app = FastHTTP()
api = Router(base_url="https://api.example.com", prefix="/v1", tags=["api"])
users = Router(prefix="/users", tags=["users"])
@users.get("/me")
async def get_me(resp: Response) -> dict:
return resp.json()
api.include_router(users)
app.include_router(api)
Final URL:
https://api.example.com/v1/users/me
Final tags:
["api", "users"]
Routers Across Multiple Files¶
In real projects, routers are usually placed in separate modules and then assembled in one place with include_router().
Example structure:
users.py¶
from fasthttp import Router
from fasthttp.response import Response
router = Router(prefix="/users", tags=["users"])
@router.get("/me")
async def get_me(resp: Response) -> dict:
return resp.json()
@router.get("/list")
async def get_users(resp: Response) -> dict:
return resp.json()
orders.py¶
from fasthttp import Router
from fasthttp.response import Response
router = Router(prefix="/orders", tags=["orders"])
@router.get("/")
async def get_orders(resp: Response) -> dict:
return resp.json()
__init__.py¶
Like in FastAPI or aiogram, you can create a central setup file that collects all routers in one place:
from fasthttp import Router
from src.clients.integrations import orders, payments, users
def setup_integrations_router() -> Router:
router = Router()
router.include_router(users.router)
router.include_router(orders.router)
router.include_router(payments.router)
return router
Attach It to the App¶
from fasthttp import FastHTTP
from src.clients.integrations import setup_integrations_router
app = FastHTTP(base_url="https://api.example.com")
app.include_router(setup_integrations_router())
This works especially well when the project grows and you want to collect routers the same way as in FastAPI:
router.include_router(users.router)
router.include_router(orders.router)
router.include_router(payments.router)
Or in a smaller aiogram-like style:
from fasthttp import Router
from src.handlers import auth, users
def setup_handlers_router() -> Router:
router = Router()
router.include_router(auth.router)
router.include_router(users.router)
return router
Relative URLs and base_url¶
If a route uses a relative path like "/me", FastHTTP needs a base_url somewhere in the router tree.
router = Router()
@router.get("/me")
async def get_me(resp: Response) -> dict:
return resp.json()
app.include_router(router, base_url="https://api.example.com")
If no base_url is provided, FastHTTP raises ValueError.
base_url in FastHTTP Constructor¶
You can set base_url directly in the FastHTTP constructor, and it will be applied to all decorators:
from fasthttp import FastHTTP
from fasthttp.response import Response
app = FastHTTP(base_url="https://api.example.com")
@app.get("/users") # → https://api.example.com/users
async def get_users(resp: Response) -> dict:
return resp.json()
@app.post("/users") # → https://api.example.com/users
async def create_user(resp: Response) -> dict:
return resp.json()
@app.graphql("/graphql") # → https://api.example.com/graphql
async def query(resp: Response) -> dict:
return {"query": "{ users { id } }"}
This works the same way for all decorators: get, post, put, patch, delete, and graphql.
Absolute URLs are used as-is and ignore base_url:
app = FastHTTP(base_url="https://api.example.com")
@app.get("https://other.com/api") # → https://other.com/api (base_url ignored)
async def other_api(resp: Response) -> dict:
return resp.json()
raise_for_status on Router Routes¶
raise_for_status can be set per-route on a router decorator. When True, that route raises FastHTTPBadStatusError on 4xx/5xx instead of returning None.
from fasthttp import FastHTTP, Router
from fasthttp.exceptions import FastHTTPBadStatusError
from fasthttp.response import Response
app = FastHTTP()
payments = Router(base_url="https://api.example.com", prefix="/payments")
@payments.post("/charge", raise_for_status=True)
async def charge(resp: Response) -> dict:
return resp.json()
@payments.get("/history")
async def history(resp: Response) -> dict | None:
if resp is None:
return None
return resp.json()
app.include_router(payments)
if __name__ == "__main__":
try:
app.run()
except FastHTTPBadStatusError as e:
print(f"Payment failed: HTTP {e.status_code}")
This works alongside the global FastHTTP(raise_for_status=True) flag — either being True is enough to raise.
When to Use Routers¶
Use routers when your project has:
- multiple API resources such as users, orders, payments
- different API versions such as
/v1and/v2 - route groups that should share tags or dependencies
- a need to keep large request collections organized