Table of Contents
15. A Simple Router — The Shape of a Request
— how a PHP application decides what to do
Before frameworks, before controllers, before middleware,
there is something very small and very human:
A request comes in.
We decide what to do with it.
We send a response back.
That’s all a router is.
Not a pattern.
Not a framework.
Not a system.
Just a decision.
Understanding this shape is enough to collaborate with AI on any routing system
— from a tiny script to a full framework —
because the mental model never changes.
1. Every request has three pieces
When PHP receives a request, it always contains:
- a method (GET, POST, etc.)
- a path (
/login,/users/123,/about) - some data (query parameters, form data, JSON, headers)
A router’s job is simply:
Match the method + path, then call the right code.
That’s it.
Everything else
— controllers, middleware, attributes, annotations —
is just decoration.
2. The smallest router we can write
Here is the simplest possible router:
$path = $_SERVER['REQUEST_URI']; if ($path === '/about') { echo 'About page'; } elseif ($path === '/contact') { echo 'Contact page'; } else { http_response_code(404); echo 'Not found'; }
This is not production code.
It’s not elegant.
But it shows the shape:
- inspect the request
- match the path
- return a response
Everything else is refinement.
3. Giving routes a home
As soon as we add more routes, the if statements become noise.
This is the moment when routing becomes a concept.
We give it a home:
class Router { private array $routes = []; public function get(string $path, callable $handler): void { $this->routes['GET'][$path] = $handler; } public function dispatch(string $method, string $path): void { $handler = $this->routes[$method][$path] ?? null; if (!$handler) { http_response_code(404); echo 'Not found'; return; } echo $handler(); } }
Now our application reads like a story:
$router->get('/about', fn() => 'About page'); $router->get('/contact', fn() => 'Contact page'); $router->dispatch($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
This is the shape of every router we’ve ever used —
just expressed gently.
4. Why this matters in the AI era
When we ask AI to “build a router,” it may generate:
- a full MVC framework
- a giant class
- middleware
- annotations
- dependency injection
- a routing table
- a dispatcher
- a controller layer
All of that is optional.
What we need is the mental model:
A router is a map from request → handler.
Everything else is convenience.
Once we hold that shape, we can steer AI:
“Make the router simpler.”
“Use closures instead of controllers.”
“Add support for dynamic parameters.”
“Return JSON instead of HTML.”
“Add middleware only for authentication.”
We’re not memorizing routing systems.
We’re shaping the conversation.
5. When to Ask AI for a Router
The moment when 'request handling' becomes a concept
Here’s what that moment looks like in practice.
We may start with something small:
“Handle a GET request to /about.”
AI gives us:
if ($_SERVER['REQUEST_URI'] === '/about') { echo 'About page'; }
Then we ask:
“Add a /contact page.”
AI adds another if.
Then we ask:
“Add /users and /products.”
More ifs.
Then we ask:
“Make it easier to add routes.”
AI hesitates or produces something messy.
This is the moment to say:
“Routing is now a concept. Give me a simple Router class that maps paths to handlers.”
AI will produce a clean router with:
- a route table
- a dispatch method
- a way to register routes
This is the literacy we're trying to develop in this wiki:
When request handling starts repeating,
ask AI for a Router.
6. The mental model in one sentence
A router is the smallest possible map from a request to a response.
Everything else is optional.
Once we see this shape, we can collaborate with AI on any routing system
— from a tiny script to a full framework —
without losing our agency.
Tony de Araujo —New York
