Routing
One file that says where every request goes
Routes are defined in routes/web.php. Each route maps a URL pattern to an Action class. Nothing is auto-discovered — if a URL works, it is because a line in this file says so.
The five verbs
$router->get('/posts', Actions\Post\Index::class);
$router->post('/posts', Actions\Post\Store::class);
$router->put('/posts/{id}', Actions\Post\Update::class);
$router->patch('/posts/{id}', Actions\Post\Update::class);
$router->delete('/posts/{id}', Actions\Post\Destroy::class);
When a request matches, the Kernel instantiates the Action and invokes it. The Action handles the rest — calling the Domain for data and passing it to the Responder.
A browser form can only send GET or POST. To reach the other three from a page, compose OverridesMethod and declare the verb in a hidden _method field.
Dynamic segments
Use curly braces to capture part of the URL:
$router->get('/posts/{slug}', Actions\Post\Show::class);
What was captured arrives on the request, so an Action never re-parses the URL:
$this->request->params['slug'] ?? ''
Captured segments are passed through exactly as they were sent. Matching ignores case — /POSTS/Hello matches /posts/{slug} — but the slug you receive is still Hello, which is what makes a mixed-case slug or a UUID routable.
A static route beats a dynamic one
$router->get('/posts/{id}', Actions\Post\Show::class);
$router->get('/posts/create', Actions\Post\Create::class);
/posts/create is the create form, not a post whose id is the word “create”, whichever order the two lines are written in.
The query string
A query string never affects which route matches. /posts?page=2 matches /posts, and the parsed query reaches the Action:
$page = $this->request->query['page'] ?? '1';
See Requests for the three places input arrives from.
View routes
Not every page needs the full ADR cycle. For static pages, return a view directly:
$router->view('/about', 'pages.about');
This renders app/Views/pages/about.php without an Action, Domain, or Responder.
Route groups
Group routes under a shared prefix:
$router->group('/admin', function (Router $router) {
$router->get('/dashboard', Actions\Admin\Dashboard::class);
$router->get('/users', Actions\Admin\Users::class);
});
This registers /admin/dashboard and /admin/users.
Reading the table back
php tether routes
php tether explain /posts/12
routes prints every registered route and flags any whose Action is missing or not routable. explain resolves one URL the way a request would and names what it captured. See The console.