5: Routing
Routing in Phlo maps a space-separated path + HTTP method to a target (usually a method).
Routes from all .phlo files are collected; the router is activated with app::route().
5.1: Basic form
route [async|both] [GET|POST|PUT|DELETE|PATCH] pad [pad2 ...] => target
- Paths are written with spaces (no
/in the route definition). - Target: a direct call or statement block.
Example:
route GET home => $this->main
method main => view($this->home)5.2: sync / async / both
| Keyword | Behavior |
|---|---|
| (omitted) | Sync only (regular HTTP) |
async |
Async only (requests from a Phlo frontend) |
both |
Sync and async allowed |
route both GET data => $this->loadData
route async POST items save => $this->saveItems5.3: Variables
Phlo parses every path segment. Segments that start with $ are variables with extra capabilities:
4.3.1 Required (passed to the target)
route GET user $id => $this->showUser($id)
method showUser($id) => view($this->profile)
4.3.2 Optional presence with ? → boolean
route GET search $full? => $this->search($full)
- Matches
/searchand/search/full. $fullis true when the segmentfullis present, otherwise false. (The implementation literally checks whether the request segment equals the name without the?.)
4.3.3 Rest (variable length) with =*
route GET file $path=* => $this->serveFile($path)
- Matches all remaining segments as one string in
$path.
4.3.4 Default value with =
route GET page $slug=home => $this->page($slug)
- Without a segment →
$slug = 'home'. - With a segment →
$slug = '<value>'.
4.3.5 Length requirement with .N
route GET code $pin.6 => $this->enter($pin)
- Matches only when the length of
$pinis exactly 6.
4.3.6 Value lists with :a,b,c
route GET report $range:daily,weekly,monthly => $this->report($range)
- The segment must be one of the listed values.
- When the segment is absent (empty) and a default is set, the default is applied.
- Otherwise the match fails.
You can combine these forms. Examples:
Enum with a required id:
route GET export $fmt:csv,json $id => $this->export($fmt, $id)
Enum with a default:
route GET theme $name:light,dark=light => $this->theme($name)5.4: Payload check with `@`
You specify exact body keys with a single @ and a comma-separated list.
The router compares this 1-to-1 with the keys from %payload (exact set; order as supplied by the engine).
route POST user @name,email => $this->createUser
method createUser => dx(%payload->name, %payload->email)
Body keys are not bound as method parameters; you read them via
%payload.
5.5: Targets
Local method
route GET profile show => $this->show
method show => view($this->profile)
External class method (static)
route GET api version $major => api::getVersion($major)
- Static calls: parentheses required, even without arguments.
- Pass path variables explicitly.
What a route may return
The dispatcher inspects the return value for exactly one thing: false means "not my route" and matching continues with the next candidate. Every other return value is discarded.
Lesson. The assumption "a route returns its response body" produces
route GET hello => 'Hello': the route matches and serves a 200 with an empty page. A route produces output exclusively throughview(),apply(),output(),location()or the%resAPI.
The false contract is also a tool: a catch-all route GET guide $slug that returns false for unknown slugs lets a literal route in a later file (GET guide index.json) still match the same URL.
5.6: Activating the router
Routes are only matched after:
app::route()
Place this call, for example, in app.phlo (or another central controller) after your app initialization and before a fallback for 404 handling.
5.7: Recommended structure
- Put routes at the top of each file.
-
Keep path and method name logically aligned:
route GET users list => $this->listUsers route POST users add => $this->addUser - Always pass variables in the target.
- Use
bothonly when an endpoint deliberately needs to be both sync and async. - Use value lists
:…instead of separateifbranches for fixed variants.