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($url, $callback)

GET

Registers a route for GET requests

post($url, $callback)

POST

Registers a route for POST requests

put($url, $callback)

PUT

Registers a route for PUT requests

patch($url, $callback)

PATCH

Registers a route for PATCH requests

delete($url, $callback)

DELETE

Registers a route for DELETE requests

options($url, $callback)

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

match($url, $callback, $methods)

Registers a route for an array of HTTP methods

any($url, $callback)

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

where($param, $pattern)

Applies a custom regex constraint to a parameter. Accepts a string or an associative array.

where_number($param)

Constrains parameter to numeric digits only: [0-9]+

where_alpha($param)

Constrains parameter to alphabetic characters only: [a-zA-Z]+

where_alphanumeric($param)

Constrains parameter to letters and digits: [a-zA-Z0-9]+

where_uuid($param)

Constrains parameter to UUID v4 format

where_ulid($param)

Constrains parameter to ULID format

where_in($param, $values)

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

middleware($middleware)

Attaches middleware to the last registered route. Accepts a string or array.

add_global_middleware($middleware)

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

name($name)

Assigns a name to the last registered route

route_name($name)

Returns the route array matching the given name, or null

route_exists($name_or_url)

Returns true if a route with the given name or URL is registered

Complete Method Reference

Method

Description

get($url, $callback)

Registers a GET route

post($url, $callback)

Registers a POST route

put($url, $callback)

Registers a PUT route

patch($url, $callback)

Registers a PATCH route

delete($url, $callback)

Registers a DELETE route

options($url, $callback)

Registers an OPTIONS route

match($url, $callback, $methods)

Registers a route for a specific set of HTTP methods

any($url, $callback)

Registers a route that responds to all HTTP methods

group($options, $callback)

Groups routes under a shared prefix and/or middleware

middleware($middleware)

Attaches middleware to the last registered route

add_global_middleware($middleware)

Registers middleware that applies to every route

where($param, $pattern)

Applies a regex constraint to a route parameter

where_number($param)

Constrains parameter to digits only

where_alpha($param)

Constrains parameter to alphabetic characters only

where_alphanumeric($param)

Constrains parameter to alphanumeric characters only

where_uuid($param)

Constrains parameter to UUID format

where_ulid($param)

Constrains parameter to ULID format

where_in($param, $values)

Constrains parameter to one of the given values

name($name)

Assigns a name to the last registered route

route_name($name)

Retrieves a route array by its assigned name

route_exists($name_or_url)

Checks if a route with the given name or URL is registered

sanitize_url($url)

Strips trailing slashes and sanitizes a URL string

initiate($url, $method)

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 raw where() 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.