Flaxon 0.3.0 and Teloce-Py 0.3.0 are available on PyPI. Release instructions are maintained on this site; source links identify the framework snapshot. Check version and upgrade guidance.
Routing
Overview
Flaxon provides a fast, flexible, and familiar routing system for building web applications and APIs. Routes are registered using decorators on your application or on reusable routers.
Features
- Decorator-based routing
- Async-first request handling
- Angle-bracket route parameters
- Nested routers
- Route groups
- Named routes
- URL generation
- Sub-application mounting
- Route inspection via CLI
Basic Routes
from flaxon import Flaxon
app = Flaxon("my-app")
@app.get("/")
async def home():
return {"message": "Hello, World!"}
@app.post("/users")
async def create_user():
return {"created": True}
@app.put("/users/<int:user_id>")
async def update_user(user_id: int):
return {
"updated": True,
"id": user_id,
}
@app.delete("/users/<int:user_id>")
async def delete_user(user_id: int):
return {
"deleted": True,
"id": user_id,
}
Supported HTTP methods
Flaxon provides convenience decorators for GET, POST, PUT, PATCH, and
DELETE. Register another method explicitly with app.route().
@app.get("/")
async def get_route():
...
@app.post("/")
async def post_route():
...
@app.put("/")
async def put_route():
...
@app.patch("/")
async def patch_route():
...
@app.delete("/")
async def delete_route():
...
@app.route("/", methods={"HEAD", "OPTIONS"})
async def metadata_route():
...
Route Parameters
Flask-Style Parameters
@app.get("/users/<int:user_id>")
async def get_user(user_id: int):
return {"id": user_id}
@app.get("/posts/<slug:slug>")
async def get_post(slug: str):
return {"slug": slug}
@app.get("/files/<path:file_path>")
async def get_file(file_path: str):
return {"path": file_path}
Supported Parameter Converters
| Converter | Description | Example |
|---|---|---|
str |
Default string | <name> |
int |
Integer | <int:user_id> |
float |
Floating point | <float:price> |
path |
Path including / |
<path:file> |
uuid |
UUID value | <uuid:token> |
slug |
URL-safe slug string | <slug:article> |
Typed Query Parameters
from flaxon import Query
@app.get("/search")
async def search(
query: str = Query("", alias="q", max_length=120),
page: int = Query(1, ge=1),
):
return {"query": query, "page": page}
Query() without a default is required. Values are coerced and invalid
values return a 422 validation response. Query declarations are included in
automatic OpenAPI documentation; see the OpenAPI guide.
Route Prefixes
from flaxon import Router
api = Router(prefix="/api/v1")
@api.get("/users")
async def users():
return []
@api.get("/posts")
async def posts():
return []
app.include_router(api)
Specificity and safe mounts
Literal routes take precedence over parameter routes, regardless of registration order. Registration order is retained only when matching routes have equal specificity.
from flaxon import Flaxon, Router
app = Flaxon("routing-example")
@app.get("/admin/<model_name>")
async def model(model_name: str):
return {"model": model_name}
@app.get("/admin/cms")
async def cms():
return {"panel": "cms"} # wins over /admin/<model_name>
api = Router(prefix="/api")
@api.get("/items/<int:item_id>")
async def item(item_id: int):
return {"id": item_id}
app.include_router(api, prefix="/v1") # GET /v1/items/7
include_router(router, prefix=...) strips the source router prefix before
applying the mount prefix, so one router can be mounted at multiple locations.
Overlapping patterns with the same HTTP method produce a registration warning.
Endpoints:
GET /api/v1/users
GET /api/v1/posts
Routers
from flaxon import Router
api = Router(prefix="/api")
@api.get("/users")
async def users():
return []
@api.post("/users")
async def create_user():
return {"created": True}
app.include_router(api)
Route Groups
from flaxon.routing import RouteGroup
admin = RouteGroup(prefix="/admin")
@admin.get("/dashboard")
async def dashboard():
return {"admin": True}
@admin.get("/users")
async def users():
return []
app.include_router(admin.as_router())
Nested Routers
from flaxon import Router
api = Router(prefix="/api")
v1 = Router(prefix="/v1")
v2 = Router(prefix="/v2")
@v1.get("/users")
async def users_v1():
return {
"version": "v1",
}
@v2.get("/users")
async def users_v2():
return {
"version": "v2",
}
api.include_router(v1)
api.include_router(v2)
app.include_router(api)
Available routes
/api/v1/users
/api/v2/users
Named Routes
@app.get(
"/users/<int:user_id>",
name="users.detail",
)
async def user_detail(user_id: int):
return {
"id": user_id,
}
Generate URLs:
url = app.url_for(
"users.detail",
user_id=42,
)
print(url)
# /users/42
Route Matching
Literal routes take precedence over dynamic routes regardless of registration order. Registration order is used only when matching routes have equal specificity.
@app.get("/users/me")
async def current_user():
return {
"username": "admin",
}
@app.get("/users/<int:user_id>")
async def user(user_id: int):
return {
"id": user_id,
}
Multiple Decorators
A single handler can respond to multiple routes.
@app.get("/")
@app.get("/home")
async def home():
return {
"message": "Welcome",
}
Route Metadata
@app.get(
"/products",
name="products.list",
tags=["Products"],
summary="List products",
)
async def products():
return []
Error Handling
from flaxon import HTTPException
@app.get("/users/<int:user_id>")
async def get_user(user_id: int):
if user_id == 0:
raise HTTPException(
400,
"Invalid user ID",
code="FX-INVALID-ID",
)
if user_id == 404:
raise HTTPException(
404,
"User not found",
code="FX-USER-404",
)
return {
"id": user_id,
"name": f"User {user_id}",
}
Mounting Applications
from flaxon import Flaxon
from flaxon.routing import Mount
admin = Flaxon("admin")
@admin.get("/")
async def dashboard():
return {
"admin": True,
}
app.include_router(
Mount("/admin", admin)
)
Routes
/admin/
API Versioning
from flaxon import Router
v1 = Router(prefix="/api/v1")
v2 = Router(prefix="/api/v2")
@v1.get("/users")
async def users_v1():
return {
"version": 1,
}
@v2.get("/users")
async def users_v2():
return {
"version": 2,
}
app.include_router(v1)
app.include_router(v2)
Route Inspection
List every registered route.
flaxon routes app:app
Example output
Method Path Name
GET / home
POST /users create_user
PUT /users/<int:user_id> update_user
DELETE /users/<int:user_id> delete_user
GET /api/v1/users users
GET /about about
Complete Example
from flaxon import Flaxon, Router
from flaxon.routing import RouteGroup
app = Flaxon("routing-demo")
@app.get("/")
async def home():
return {
"message": "Welcome to Flaxon",
}
@app.get("/users/<int:user_id>")
async def user(user_id: int):
return {
"id": user_id,
"name": f"User {user_id}",
}
api = Router(prefix="/api/v1")
@api.get("/products")
async def products():
return [
{
"id": 1,
"name": "Laptop",
},
{
"id": 2,
"name": "Keyboard",
},
]
app.include_router(api)
admin = RouteGroup(prefix="/admin")
@admin.get("/dashboard")
async def dashboard():
return {
"users": 152,
"orders": 89,
}
app.include_router(admin.as_router())
@app.get("/about", name="about")
async def about():
return {
"framework": "Flaxon",
"version": "1.0.0",
}
about_url = app.url_for("about")
print(about_url)
Best Practices
- Group related routes using
Router. - Use API versioning for public APIs.
- Register specific routes before dynamic routes.
- Use named routes for URL generation.
- Keep route handlers focused on request handling.
- Move business logic into services.
- Validate request data using schemas.
- Return consistent JSON responses.
- Organize large applications into multiple routers.
- Mount sub-applications when building modular systems.
Use this capability in a full-stack app
Flaxon serves Python APIs and Teloce interfaces in one project. Keep validation, authorization and privileged operations on the server; components call those endpoints and present their results. Follow the full-stack lessons and Teloce integration reference to connect this capability to pages, components and application modules.