Routing¶
Asok uses a file-based router. The directory structure of src/pages/ defines your URLs.
Basic routing¶
URL |
File path |
|---|---|
|
|
|
|
|
|
|
|
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 |
|---|---|---|
|
|
|
|
|
|
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 |
|---|---|
|
|
|
|
|
|
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>
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.paramscontains{ id: '123' }.window.AsokRouter.route.pathis"/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();