# HTTP Routing

- [Basic Routing](#basic-routing)
- [Cache Routing](#cache-routing)
- [Domain Routing](#domain-routing)
- [Route Parameters](#route-parameters)
    - [Required Parameters](#required-parameters)
    - [Optional Parameters](#optional-parameters)
    - [Regular Expression Constraints](#parameters-regular-expression-constraints)
- [Named Routes](#named-routes)
- [Route Groups](#route-groups)
    - [Middleware](#route-group-middleware)
    - [Namespaces](#route-group-namespaces)
    - [Route Prefixes](#route-group-prefixes)

<a name="basic-routing"></a>
## Basic Routing

You will define All the routes for your application in the `routes/web.php` file. The most basic Maravel routes simply accept a URI and a `Closure`:

    $router->get('foo', function () {
        return 'Hello World';
    });

    $router->post('foo', function () {
        //
    });

## Cache Routing

These commands are available in Maravel template. Routes are auto-cached on `--no-dev` composer environments.

    php artisan route:cache

    php artisan route:clear

## Domain Routing

Maravel enables restricting routes to specific `domain` and generating **absolute URLs** for named routes via `route` function.

To enable domain enforcement and absolute URL generation, the domain parameter must include valid URLs without trailing slash or port.
   - Correct:

    'domain' => 'https://api.example.com'
    'domain' => ['https://api.example.com', 'https://api-custom.example.com']

   - Incorrect:
   
    'domain' => 'api.example.com'
    'domain' => 'https://api.example.com/'
    'domain' => 'https://api.example.com:80'

If a `domain` is provided without a scheme (e.g., api.example.com) or app.url has no scheme:
   - named routes will fall back to relative paths (e.g., /users) because the system cannot safely assume the intended protocol.
   - the domain check will be skipped, and the route will resolve on any host hitting the application.
 
When a valid URL is provided in the route group OR app.url config, all named routes (`route('name')`) will automatically return the full absolute URL.  Example: https://api.example.com/v1/profile

The matching logic is port-agnostic. A configuration for http://localhost will correctly match a request to http://localhost:8000, making it safe for local microservice development.

> **Note:**
>
> All aliases and URIs must be unique despite having multiple domains! Use prefixes for route uri to accomplish that.
>
> When domains is a list of urls, `route('alias')` will use/return the last url from the list.
>
> When same uri is registered multiple times `route('alias')` will use/return the last url from the last registration.
>
> In debug mode same alias used multiple times will be logged.
> 
> The `domain` key can be used in route groups.
> 
> Create and use/uncomment the GLOBAL (mandatory GLOBAL) middleware \App\Http\Middleware\TrustProxies::class, in \App\Application::registerExplicitBindingsMap or in bootstrap/app.php:
    
    $app->middleware([
        \App\Http\Middleware\TrustProxies::class,
    ]);

This is needed for proper domain check from current request. See Maravelith's [documentation](https://macropay-solutions.github.io/maravelith-docs/requests.html#configuring-trusted-proxies) for more details. Failing to do this will silently result in 404 responses!

#### Available Router Methods

The router allows you to register routes that respond to any HTTP verb:

    $router->get($uri, $callback);
    $router->post($uri, $callback);
    $router->put($uri, $callback);
    $router->patch($uri, $callback);
    $router->delete($uri, $callback);
    $router->options($uri, $callback);
    $router->match(['GET', 'POST'], $uri, $callback);

<a name="route-parameters"></a>
## Route Parameters

<a name="required-parameters"></a>
### Required Parameters

Of course, sometimes you will need to capture segments of the URI within your route. For example, you may need to capture a user's ID from the URL. You may do so by defining route parameters:

    $router->get('user/{id}', function ($id) {
        return 'User '.$id;
    });

You may define as many route parameters as required by your route:

    $router->get('posts/{postId}/comments/{commentId}', function ($postId, $commentId) {
        //
    });

Route parameters are always encased within "curly" braces. The parameters will be passed into your route's `Closure` when the route is executed.

> **Note:** Route parameters cannot contain the `-` character. Use an underscore (`_`) instead.

<a name="optional-parameters"></a>
### Optional Parameters

You may define optional route parameters by enclosing part of the route URI definition in `[...]`. So, for example, `/foo[bar]` will match both `/foo` and `/foobar`. Optional parameters are only supported in a trailing position of the URI. In other words, you may not place an optional parameter in the middle of a route definition:

    $router->get('user[/{name}]', function ($name = null) {
        return $name;
    });

<a name="parameters-regular-expression-constraints"></a>
### Regular Expression Constraints

You may constrain the format of your route parameters by defining a regular expression in your route definition:

    $router->get('user/{name:[A-Za-z]+}', function ($name) {
        //
    });

<a name="named-routes"></a>
## Named Routes

Named routes allow the convenient generation of URLs or redirects for specific routes. You may specify a name for a route using the `as` array key when defining the route:

    $router->get('profile', ['as' => 'profile', function () {
        //
    }]);

You may also specify route names for controller actions:

    $router->get('profile', [
        'as' => 'profile', 'uses' => 'UserController@showProfile'
    ]);

#### Generating URLs To Named Routes

Once you have assigned a name to a given route, you may use the route's name when generating URLs or redirects via the global `route` function:

    // Generating URLs...
    $url = route('profile');

    // Generating Redirects...
    return redirect()->route('profile');

If the named route defines parameters, you may pass the parameters as the second argument to the `route` function. The given parameters will automatically be inserted into the URL in their correct positions:

    $router->get('user/{id}/profile', ['as' => 'profile', function ($id) {
        //
    }]);

    $url = route('profile', ['id' => 1]);

<a name="route-groups"></a>
## Route Groups

Route groups allow you to share route attributes, such as middleware or namespaces, across a large number of routes without needing to define those attributes on each individual route. Shared attributes are specified in an array format as the first parameter to the `$router->group` method.

To learn more about route groups, we'll walk through several common use-cases for the feature.

<a name="route-group-middleware"></a>
### Middleware

To assign middleware to all routes within a group, you may use the `middleware` key in the group attribute array. Middleware will be executed in the order you define this array:

    $router->group(['middleware' => 'auth'], function () use ($router) {
        $router->get('/', function () {
            // Uses Auth Middleware
        });

        $router->get('user/profile', function () {
            // Uses Auth Middleware
        });
    });

<a name="route-group-namespaces"></a>
### Namespaces

Another common use-case for route groups is assigning the same PHP namespace to a group of controllers. You may use the `namespace` parameter in your group attribute array to specify the namespace for all controllers within the group:

    $router->group(['namespace' => 'Admin'], function() use ($router)
    {
        // Using The "App\Http\Controllers\Admin" Namespace...

        $router->group(['namespace' => 'User'], function() use ($router) {
            // Using The "App\Http\Controllers\Admin\User" Namespace...
        });
    });

<a name="route-group-prefixes"></a>
### Route Prefixes

The `prefix` group attribute may be used to prefix each route in the group with a given URI. For example, you may want to prefix all route URIs within the group with `admin`:

    $router->group(['prefix' => 'admin'], function () use ($router) {
        $router->get('users', function () {
            // Matches The "/admin/users" URL
        });
    });

You may also use the `prefix` parameter to specify common parameters for your grouped routes:

    $router->group(['prefix' => 'accounts/{accountId}'], function () use ($router) {
        $router->get('detail', function ($accountId) {
            // Matches The "/accounts/{accountId}/detail" URL
        });
    });


> **Note**
> Maravel-Framework version [10.67.0](https://github.com/macropay-solutions/maravel-framework/releases/tag/10.67.0) brings new, safer and faster Router (tree logic) to [Maravel 10.52.48](https://github.com/macropay-solutions/maravel/releases/tag/10.52.48).
> 
> The important change is that instead of 405, 404 http response code will be returned.

> **CRITICAL ARCHITECTURAL WARNING**
>
> Because Maravel's high-performance router utilizes native `strtok()` loops to parse URI nodes with zero memory allocations, **this framework is strictly designed for a stateless, isolated PHP-FPM execution architecture.**
>
> Do **NOT** run Maravel with long-running, multithreaded, or coroutine-based application servers (such as **Laravel Octane, Swoole, OpenSwoole, or RoadRunner**).
>
> Because `strtok()` relies on a single global internal pointer within the PHP thread state, concurrent asynchronous requests sharing the same process worker will overwrite each other's routing tokens mid-flight. This will result in critical security vulnerabilities, including routing desynchronization, cross-user data leaks, and authentication middleware bypasses.