Routing#
Keywords: dynamic urls, routing params, index files, pure html, custom error pages, page.py, static files, url parameters, index.py
Asok uses a file-based router. The directory structure of src/pages/ defines your URLs.
Basic routing#
| URL | File path |
|---|---|
/ | src/pages/page.py (or page.html) |
/about | src/pages/about/page.py |
/contact | src/pages/contact/page.py |
/blog | src/pages/blog/page.py |
Index files#
By default, Asok looks for a file named page.py or page.html inside a folder.
src/pages/page.py→/src/pages/auth/login/page.py→/auth/login
You can change this default name in your configuration: app.config['INDEX'] = "index" would look for index.py.
Dynamic parameters#
To capture variables from the URL, use square brackets in the folder name.
| URL | Folder path | Param |
|---|---|---|
/user/42 | src/pages/user/[id]/page.py | request.params['id'] == "42" |
/blog/my-post | src/pages/blog/[slug]/page.py | request.params['slug'] == "my-post" |
Parameter types#
You can optionally specify a type for automatic validation and conversion:
[id:int]— matches digits only,request.params['id']is a Pythonint[name:str]— matches any string (default)[uid:uuid]— matches a UUID string[path:path]— matches multiple segments (e.g./docs/[path:path]matches/docs/api/routing)
Example: src/pages/product/[id:int]/page.py If a user visits /product/abc, Asok returns a 404 Not Found because "abc" is not an integer.
Request methods#
Every page can handle different HTTP methods by defining get(), post(), put(), delete(), etc.
# src/pages/contact/page.py
def get(request):
return request.html('contact.html')
def post(request):
# Process form...
request.flash('success', 'Thank you!')
return request.redirect('/contact')
If a specific method is not defined, Asok falls back to the render() function. If neither is defined, it returns 405 Method Not Allowed.
Pure HTML pages#
For simple static pages, you don't even need a .py file. Just create a .html file:
src/pages/about/page.html → serves this HTML at /about.
Static files#
Files in src/partials/ are served at /static/.
| File path | URL |
|---|---|
src/partials/css/base.css | /css/base.css |
src/partials/js/base.js | /js/base.js |
src/partials/images/logo.svg | /images/logo.svg |
Use static() in templates:
<link rel="stylesheet" href="{{ static('css/base.css') }}">
<img src="{{ static('images/logo.svg') }}">
Custom error pages#
Create a page for any HTTP error code:
src/pages/404/page.html: Custom 404 pagesrc/pages/403/page.html: Custom 403 page (triggered by CSRF failures or security protection)src/pages/500/page.html: Custom 500 pagesrc/pages/429/page.html: Custom 429 page (Rate limiting)
<!-- src/pages/404/page.html -->
{% extends "html/base.html" %}
{% block main %}
<h1>Page not found</h1>
<p>Sorry, this page doesn't exist.</p>
<a href="/">Go home</a>
{% endblock %}
In production (DEBUG=false), the 500 page is shown instead of the raw error.
Client-Side Single Page Application (SPA) Router#
In addition to file-based backend routing, Asok provides a native declarative SPA router (asok-router) with deterministic transitions, dynamic parameters, and zero-reload navigation.
Basic SPA Router Setup#
Wrap your page views inside a container marked with asok-router, and define routes using <template asok-route="/path">:
<main asok-router asok-transition="slide-left 200">
<!-- Home Route -->
<template asok-route="/" asok-meta:title="Home - Asok App">
<div class="p-8">
<h1 class="text-3xl font-bold">Welcome Home</h1>
<a asok-link="/contact" class="text-blue-600">Contact page →</a>
</div>
</template>
<!-- Contact Route -->
<template asok-route="/contact" asok-meta:title="Contact Us">
<div class="p-8" asok-state="{ name: '' }">
<h1 class="text-3xl font-bold">Contact Us</h1>
<form asok-fetch-post="/api/contact" asok-reset class="mt-4">
<input asok-model="name" type="text" name="name" required>
<button type="submit">Send</button>
</form>
</div>
</template>
</main>
SPA Navigation Links (asok-link)#
Use asok-link on links or buttons for seamless client-side SPA navigation without full page reloads.
Standard HTML href with asok-link (Recommended for SEO & Accessibility):#
Specify the target URL using the standard href attribute and attach asok-link:
<nav>
<a href="/" asok-link asok-active-class="font-bold underline">Home</a>
<a href="/contact" asok-link asok-active-class="font-bold underline">Contact</a>
</nav>
Compact syntax with asok-link="/path":#
You can also declare the path directly within asok-link. Asok automatically populates the href attribute on the <a> element:
<nav>
<a asok-link="/" asok-active-class="font-bold underline">Home</a>
<a asok-link="/contact" asok-active-class="font-bold underline">Contact</a>
</nav>
Active Classes (asok-active-class)#
The asok-active-class attribute specifies the CSS class(es) to add automatically when the current URL matches the link: - Default class: 'active' if asok-active-class is omitted. - Multiple space-separated classes supported: You can provide multiple classes (e.g. Tailwind utility classes: asok-active-class="font-bold underline text-blue-600"). Asok automatically splits and applies each class individually to classList without throwing token syntax errors.
Programmatic Navigation#
Navigate dynamically from JavaScript:
// Navigate to a route
window.AsokRouter.navigate('/contact');
// Replace history entry
window.AsokRouter.navigate('/dashboard', true);
Listening to Route Changes (onRouteChange)#
Execute custom logic, track analytics, or update component states whenever the active route changes using onRouteChange (or its alias afterEach):
// Listen to all route changes
window.AsokRouter.onRouteChange((route) => {
console.log("New route:", route.path);
console.log("Parameters:", route.params);
console.log("Query parameters:", route.query);
console.log("Hash:", route.hash);
if (route.path === '/contact') {
// Specific logic for contact page!
console.log("Initializing contact form");
} else if (route.path === '/about') {
// Specific logic for about page!
console.log("Loaded About page");
}
});
Note: The callback passed to
onRouteChangeis executed immediately upon registration with the current active route, and then automatically every time the route changes (either viawindow.AsokRouter.navigate()or browser back/forward buttons).
Native DOM Event (asok:routechange)#
Asok also dispatches a standard CustomEvent on window whenever navigation occurs:
window.addEventListener('asok:routechange', (event) => {
console.log("New route:", event.detail.path);
console.log("Parameters:", event.detail.params);
console.log("Query:", event.detail.query);
console.log("Hash:", event.detail.hash);
});
Inspecting Current Route State#
You can read the current route details synchronously at any point:
// Active route state object (reactive)
console.log(window.AsokRouter.route.path); // e.g. "/contact"
console.log(window.AsokRouter.route.params); // e.g. { id: "42" }
console.log(window.AsokRouter.route.query); // e.g. { tab: "messages" }
console.log(window.AsokRouter.route.hash); // e.g. "#section-2"
// Direct property getters are also available
console.log(window.AsokRouter.path);
console.log(window.AsokRouter.params);
console.log(window.AsokRouter.query);
console.log(window.AsokRouter.hash);
Dynamic Route Parameters (:param)#
Define dynamic segments in client-side templates using :paramName:
<main asok-router>
<!-- Dynamic profile route -->
<template asok-route="/user/:id" asok-meta:title="User Profile">
<div class="p-8">
<h1 class="text-2xl font-bold">User Profile</h1>
<p>User ID: <span asok-text="window.AsokRouter.params.id"></span></p>
</div>
</template>
</main>
When navigating to /user/123: - window.AsokRouter.route.params contains { id: '123' }. - window.AsokRouter.route.path is "/user/123".
Route Pattern Matching (matchPattern)#
Test whether a URL matches a route pattern and extract its parameters:
const params = window.AsokRouter.matchPattern('/user/:id', '/user/42');
// params => { id: '42' }
const mismatch = window.AsokRouter.matchPattern('/about', '/contact');
// mismatch => null
Manual Router Update (update)#
If you dynamically inject new route templates or modify DOM nodes at runtime, trigger a router update:
window.AsokRouter.update();
Was this page helpful?