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|QUERY] pad [pad2 ...] => target

Example:

route GET home => $this->main
method main => view($this->home)

QUERY (RFC 10008) is a safe, idempotent read that carries a request body, for a lookup whose parameters do not fit cleanly in a URL. %payload decodes the QUERY body the same way it decodes POST (JSON, form-urlencoded, multipart), and HTTP() takes a matching QUERY: argument for calling out to another QUERY endpoint.

route QUERY search => $this->search
method search => dx(%payload->filters)

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->saveItems

5.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)

4.3.3 Rest (variable length) with =*

route GET file $path=* => $this->serveFile($path)

4.3.4 Default value with =

route GET page $slug=home => $this->page($slug)

4.3.5 Length requirement with .N

route GET code $pin.6 => $this->enter($pin)

4.3.6 Value lists with :a,b,c

route GET report $range:daily,weekly,monthly => $this->report($range)

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)

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 through view(), apply(), output(), location() or the %res API.

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.

Principle: respond without a redirect. Request and response are decoupled, so a route can forward the work to another routine and return its output, answering in one request instead of redirecting. For an async request, return apply()/view() directly with path: (the SPA swaps in place, no second request); for a sync POST that just re-shows a page, forward to that page's routine rather than calling location(). location() stays the right tool for a sync request that must canonicalize the URL (POST-redirect-GET, or a hard navigation), which the engine itself does when a sync view() receives a differing string path:. The aim is to avoid the unnecessary roundtrip, not to ban redirects.

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

We use essential cookies to make this site work. With your permission we also use analytics to improve the site.