Routes
LavaLust provides a simple and flexible routing system supporting closures, controllers, middleware, route groups, named routes, parameter constraints, and more.
All routes are defined in app/config/routes.php.
HTTP Method Routes
Each method registers a route that responds to a specific HTTP verb.
GET:
<?php
$router->get('/users', function() {
echo "List of users";
});
POST:
<?php
$router->post('/users', function() {
echo "Create a user";
});
PUT:
<?php
$router->put('/users/{id}', function($id) {
echo "Update user " . $id;
});
PATCH:
<?php
$router->patch('/users/{id}', function($id) {
echo "Partially update user " . $id;
});
DELETE:
<?php
$router->delete('/users/{id}', function($id) {
echo "Delete user " . $id;
});
OPTIONS:
<?php
$router->options('/users', function() {
echo "Options for users";
});
Method |
HTTP Verb |
Description |
|---|---|---|
|
GET |
Registers a route for GET requests |
|
POST |
Registers a route for POST requests |
|
PUT |
Registers a route for PUT requests |
|
PATCH |
Registers a route for PATCH requests |
|
DELETE |
Registers a route for DELETE requests |
|
OPTIONS |
Registers a route for OPTIONS requests |
Matching Multiple Methods
match — respond to a specific set of HTTP methods:
<?php
$router->match('/contact', function() {
echo "Handles GET and POST";
}, ['get', 'post']);
any — respond to all HTTP methods (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS):
<?php
$router->any('/ping', function() {
echo "Responds to any method";
});
Method |
Description |
|---|---|
|
Registers a route for an array of HTTP methods |
|
Registers a route that responds to all HTTP methods |
Using Controllers
Instead of closures you can point a route to a controller method using :: , -> ,
or @ as a separator:
<?php
// Recommended separator
$router->get('/users', 'UserController::index');
$router->get('/users/{id}', 'UserController::show');
$router->post('/users', 'UserController::store');
$router->put('/users/{id}', 'UserController::update');
$router->delete('/users/{id}','UserController::destroy');
// Alternative separators (all equivalent)
$router->get('/users', 'UserController->index');
$router->get('/users', 'UserController@index');
// Controller with no method — calls index() by default
$router->get('/home', 'HomeController');
Note
The controller file must exist at app/controllers/ControllerName.php.
A RuntimeException is thrown if the controller file or method cannot be found.
Dynamic Route Parameters
Define dynamic segments using curly braces {}. They are automatically injected
into the closure or controller method as arguments.
<?php
// Single parameter
$router->get('/user/{id}', function($id) {
echo "User ID: " . $id;
});
// Multiple parameters
$router->get('/post/{year}/{slug}', function($year, $slug) {
echo "Post: " . $slug . " (" . $year . ")";
});
// Optional parameter (append ?)
$router->get('/user/{id}/{tab?}', function($id, $tab = null) {
echo "User: " . $id . " Tab: " . $tab;
});
Accessing ``http://yourdomain.com/user/42``:
User ID: 42
Regular Expression Constraints
Use where() to constrain the format of route parameters.
Single constraint:
<?php
$router->get('/user/{name}', function($name) {
echo $name;
})->where('name', '[A-Za-z]+');
Multiple constraints via array:
<?php
$router->get('/user/{id}/{name}', function($id, $name) {
echo $id . " - " . $name;
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
Note
If the incoming request does not match the constraint pattern, a 404 response is returned automatically.
Constraint Helper Methods
For common patterns, shorthand helpers are available and can be chained:
<?php
// Numeric only
$router->get('/user/{id}', function($id) {})->where_number('id');
// Alphabetic only
$router->get('/user/{name}', function($name) {})->where_alpha('name');
// Alphanumeric
$router->get('/user/{username}', function($username) {})->where_alphanumeric('username');
// UUID
$router->get('/order/{uuid}', function($uuid) {})->where_uuid('uuid');
// ULID
$router->get('/item/{ulid}', function($ulid) {})->where_ulid('ulid');
// Enumerated values
$router->get('/category/{type}', function($type) {
// ...
})->where_in('type', ['movie', 'song', 'painting']);
// Chaining multiple helpers
$router->get('/user/{id}/{name}', function($id, $name) {
// ...
})->where_number('id')->where_alpha('name');
Method |
Description |
|---|---|
|
Applies a custom regex constraint to a parameter. Accepts a string or an associative array. |
|
Constrains parameter to numeric digits only: |
|
Constrains parameter to alphabetic characters only: |
|
Constrains parameter to letters and digits: |
|
Constrains parameter to UUID v4 format |
|
Constrains parameter to ULID format |
|
Constrains parameter to one of the provided values |
Grouping Routes
Use group() to apply a shared prefix and/or middleware to a set of routes.
Prefix only:
<?php
$router->group(['prefix' => '/admin'], function($router) {
$router->get('/dashboard', function() {
echo "Admin Dashboard";
});
$router->get('/users', function() {
echo "Manage Users";
});
});
// Registered routes: /admin/dashboard, /admin/users
Prefix with middleware:
<?php
$router->group(['prefix' => '/admin', 'middleware' => 'AuthMiddleware'], function($router) {
$router->get('/dashboard', 'AdminController::dashboard');
$router->get('/settings', 'AdminController::settings');
});
Nested groups:
<?php
$router->group(['prefix' => '/api'], function($router) {
$router->group(['prefix' => '/v1', 'middleware' => 'ApiMiddleware'], function($router) {
$router->get('/users', 'Api\UserController::index');
});
});
// Registered route: /api/v1/users
Note
Group prefix and middleware are restored automatically after the group callback executes, so they do not leak into routes defined outside the group.
Middleware
Middleware can be applied globally, per group, or per individual route.
Per-route middleware:
<?php
$router->get('/dashboard', 'DashboardController::index')
->middleware('AuthMiddleware');
// Multiple middleware
$router->get('/admin', 'AdminController::index')
->middleware(['AuthMiddleware', 'RoleMiddleware']);
Global middleware (runs on every request):
<?php
$router->add_global_middleware('CorsMiddleware');
// Multiple global middleware
$router->add_global_middleware(['CorsMiddleware', 'LogMiddleware']);
Method |
Description |
|---|---|
|
Attaches middleware to the last registered route. Accepts a string or array. |
|
Registers middleware that runs on every matched route. Accepts a string or array. |
Named Routes
Assign a name to a route for easy reference and lookup.
Naming a route:
<?php
$router->get('/user/profile', 'UserController::profile')->name('user.profile');
Looking up a route by name:
<?php
$route = $router->route_name('user.profile');
// Returns the full route array, or null if not found
Checking if a route exists (by name or URL):
<?php
if ($router->route_exists('user.profile')) {
echo "Route exists";
}
if ($router->route_exists('/user/profile')) {
echo "URL is registered";
}
Method |
Description |
|---|---|
|
Assigns a name to the last registered route |
|
Returns the route array matching the given name, or |
|
Returns |
Complete Method Reference
Method |
Description |
|---|---|
|
Registers a GET route |
|
Registers a POST route |
|
Registers a PUT route |
|
Registers a PATCH route |
|
Registers a DELETE route |
|
Registers an OPTIONS route |
|
Registers a route for a specific set of HTTP methods |
|
Registers a route that responds to all HTTP methods |
|
Groups routes under a shared prefix and/or middleware |
|
Attaches middleware to the last registered route |
|
Registers middleware that applies to every route |
|
Applies a regex constraint to a route parameter |
|
Constrains parameter to digits only |
|
Constrains parameter to alphabetic characters only |
|
Constrains parameter to alphanumeric characters only |
|
Constrains parameter to UUID format |
|
Constrains parameter to ULID format |
|
Constrains parameter to one of the given values |
|
Assigns a name to the last registered route |
|
Retrieves a route array by its assigned name |
|
Checks if a route with the given name or URL is registered |
|
Strips trailing slashes and sanitizes a URL string |
|
Dispatches the request; called internally by the framework |
Tips and Best Practices
Use closures for small, simple routes or quick prototypes.
Use controllers for anything beyond a few lines of logic to keep your code organized.
Apply middleware at the group level rather than per-route when multiple routes share the same access rules.
Use named routes (
name()) instead of hardcoding URLs so a single path change does not break your application.Use constraint helpers (
where_number,where_uuid, etc.) instead of rawwhere()regex for cleaner, more readable route definitions.Always validate route parameters inside controllers even when constraints are set — constraints only control URL matching, not business-level validation.