Routing
In Koyo the file tree is the route table. No central router file to
edit, the path to a page.py decides the URL.
Path conventions#
| File | URL |
|---|---|
app/page.py |
/ |
app/about/page.py |
/about |
app/blog/[slug]/page.py |
/blog/:slug |
The scaffold ships only the first row: a single home page with a
call to action linking to the Koyo documentation. The other rows are
what you add yourself: folders inside app/ become path
segments, and a page.py inside any folder becomes the
handler for that path.
The page() function#
Each page module exports a page() function that returns HTML:
# app/post/page.py
from koyoapp.html import div, h1, p
def page():
return div(class_="max-w-2xl mx-auto py-12")[
h1("About Koyo"),
p("A static-first web framework."),
]
The return value can be an element built from the koyoapp.html
tag factories or a plain string. For static routes page()
takes no arguments.
Dynamic segments#
A folder whose name is wrapped in brackets becomes a parameter. The
segment value is passed to page() as a keyword argument:
# app/blog/[slug]/page.py
from koyoapp.html import article, h1
def page(slug):
return article(class_="prose")[
h1("Post " + slug),
]
Add a file at app/blog/[slug]/page.py and it renders
URLs such as /blog/hello-world.
HTTP methods#
Every route accepts the standard methods: GET, HEAD, POST, PUT,
PATCH, and DELETE. The session counter on the scaffold home page
posts through use_state's internal route and swaps in
a fresh render, see session state.
Missing pages#
When no route matches, Koyo returns a 404 page. A file in
public/ is served before falling back to routing, so
static files take priority for their paths.
During development with KOYO_DEV=1 set, unhandled errors
show a debug page with a traceback. Outside of development, Koyo
returns a generic internal server error and keeps the traceback in
the dev server log.
Internal routes#
Koyo reserves the /__koyo_state/... namespace for session
state updates. You do not need to create or manage these routes; they
are handled for you when a page uses use_state.
The vendored htmx library is served at /htmx.min.js.