> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apivalk.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Route

> The `Route` class is a data carrier that represents a single endpoint in your API. It encapsulates all the necessary information to map a URL and HTTP method to a specific action.

## Properties

A `Route` instance contains the following information:

* **URL**: The path template for the endpoint (e.g., `/api/v1/users/{id}`).
* **Method**: An implementation of `MethodInterface` representing the allowed HTTP verb (GET, POST, etc.).
* **Description**: An optional human-readable description used for documentation (OpenAPI).
* **Tags**: A collection of `TagObject` instances used for grouping endpoints in documentation.
* **Security Requirements**: A `RouteAuthorization` instance defining the authentication and authorization needed for the route.
* **Rate Limit**: An optional `RateLimitInterface` implementation defining the rate limiting rules for the endpoint.
* **Sorting**: A collection of `Sort` instances defining allowed sorting fields for the endpoint.
* **Pagination**: A `Pagination` instance defining the pagination strategy (Page, Offset, or Cursor).
* **Filtering**: A collection of `FilterInterface` instances defining allowed filtering fields for the endpoint.
* **Path Properties**: Typed `AbstractProperty` instances defining each path parameter (e.g. `{id}`, `{user_uuid}`), declared via chained `pathProperty()` calls.

## Path Parameters

Routes support dynamic path parameters using the `{parameterName}` syntax. Parameter names may contain letters, digits, and underscores (`[a-zA-Z0-9_]`).

Define the type and description of each path parameter directly on the route using `pathProperty()`:

```php theme={null}
use apivalk\apivalk\Documentation\Property\StringProperty;
use apivalk\apivalk\Documentation\Property\IntegerProperty;

// Single parameter
Route::get('/users/{id}')
    ->pathProperty(new IntegerProperty('id', 'User ID'));

// Multiple parameters — chain the calls
Route::get('/orgs/{org_id}/users/{user_id}')
    ->pathProperty(new IntegerProperty('org_id', 'Organisation ID'))
    ->pathProperty(new StringProperty('user_id', 'User UUID'));
```

This is the preferred way to declare path parameters. Defining them on the route means the type, validation, and OpenAPI documentation are all co-located with the URL pattern rather than split across a separate request class.

Path parameters defined via `pathProperty()` are automatically:

* **Validated and type-cast** when the request is populated
* **Included in the OpenAPI spec** as `in: path` parameters
* **Included in the generated path shape** for IDE type hints

### Validators

Any property constraint supported by Apivalk can be applied to a path parameter:

```php theme={null}
use apivalk\apivalk\Documentation\Property\IntegerProperty;
use apivalk\apivalk\Documentation\Property\StringProperty;

Route::get('/users/{id}')
    ->pathProperty(
        (new IntegerProperty('id', 'User ID'))
            ->setMinimumValue(1)
    );

Route::get('/articles/{slug}')
    ->pathProperty(
        (new StringProperty('slug', 'Article slug'))
            ->setMinLength(1)
            ->setMaxLength(100)
            ->setPattern('/^[a-z0-9-]+$/')
    );
```

Constraints are serialized with the route when route caching is enabled and are fully restored on cache load.

### Path parameters are always required

`pathProperty()` always enforces `isRequired(true)` regardless of what is set on the property. Path parameters are structurally required — the route only matches when they are present in the URL. Marking one optional would produce an invalid OpenAPI spec (`required: false` on a `path` parameter violates the OpenAPI specification).

### Accessing path parameters

```php theme={null}
public function __invoke(ApivalkRequestInterface $request): AbstractApivalkResponse
{
    $id = $request->path()->id;           // magic accessor
    $id = $request->path()->get('id');    // explicit accessor
}
```

### Backward compatibility

Path properties can also be declared in the request class via `addPathProperty()` in `getDocumentation()`. Both sources are merged — you can use either or both. `pathProperty()` on the route is preferred for new code.

## Security and Authorization

Security requirements are defined on a per-route basis using the `RouteAuthorization` object. This allows you to specify which authentication scheme (e.g., Bearer, OAuth2) is required and what granular scopes and permissions the user must have.

### Public Route

If no `RouteAuthorization` is provided (default), the route is fully public. Anyone can access it.

```php theme={null}
Route::get('/about')->description('About page');
```

### Authenticated Route (No Specific Scopes)

To require authentication without enforcing specific scopes or permissions, pass only the security scheme name. The `SecurityMiddleware` will reject anonymous users with a `401 Unauthorized` but allow any authenticated identity through.

```php theme={null}
use apivalk\apivalk\Router\Route\Route;
use apivalk\apivalk\Security\RouteAuthorization;

Route::get('/me/profile')
    ->description('Get my profile')
    ->routeAuthorization(new RouteAuthorization('BearerAuth'));
```

### Scoped Route (Specific Scopes and Permissions)

To require both authentication and specific scopes/permissions:

```php theme={null}
use apivalk\apivalk\Router\Route\Route;
use apivalk\apivalk\Security\RouteAuthorization;

Route::post('/orders')
    ->description('Create order')
    ->routeAuthorization(
        new RouteAuthorization('apiKey', ['accounting:orders'], ['accounting:orders:create'])
    );
```

### Optional Security (Public with Identity)

If you want a route to be public but optionally use identity information when a token is provided, leave `RouteAuthorization` as `null`. The `AuthenticationMiddleware` will still populate the identity if a valid token is present, so you can check `$request->getAuthIdentity()->isAuthenticated()` in your controller.

For more details on how the security system works, check the [Security Overview](/security/index).

## Integration with Documentation

The `Route` class implements `JsonSerializable`, allowing it to be easily exported for OpenAPI (Swagger) generation. It includes helper methods for:

* `jsonSerialize()`: Converts the route and its metadata into a format suitable for JSON export.
* `static byJson(string $json)`: Hydrates a `Route` object from a JSON string, which is used when loading routes from the router cache.

## Usage in Controllers

In an Apivalk application, you typically don't instantiate `Route` objects manually. Instead, you define them in your controller's static `getRoute()` method:

```php theme={null}
public static function getRoute(): Route
{
    return Route::get('/v1/hello-world')
                  ->description('A simple hello world endpoint')
                  ->tag(new TagObject('Greeting', 'Endpoints for saying hello'));
}
```

## Rate Limiting

You can add rate limiting to a route by providing a rate limit object as the last argument to the `Route` constructor:

```php theme={null}
use apivalk\apivalk\Router\RateLimit\IpRateLimit;

public static function getRoute(): Route
{
    return new Route::get('/v1/sensitive-data')
                      ->description('Access sensitive data')
                      ->rateLimit(new IpRateLimit('sensitive_access', 5, 60));
}
```

For more details on available rate limiting strategies, see the [Rate Limit](/routing/rate-limit) documentation.

## Sorting

You can define which fields are allowed for sorting by using the `sorting()` method. This takes an array of `Sort` objects:

```php theme={null}
use apivalk\apivalk\Router\Route\Sort\Sort;

public static function getRoute(): Route
{
    return Route::get('/v1/users')
                  ->description('List users')
                  ->sorting([
                      Sort::asc('id'),
                      Sort::desc('created_at')
                  ]);
}
```

The `sorting()` method also defines the **default sorting** for the route. If a user does not provide an `order_by` query parameter, the `sorting()` bag on the request object will be automatically populated with these defined values.

## Pagination

You can enable pagination for a route using the `pagination()` method. This takes a `Pagination` object:

```php theme={null}
use apivalk\apivalk\Router\Route\Pagination\Pagination;

public static function getRoute(): Route
{
    return Route::get('/v1/users')
                  ->description('List users')
                  ->pagination(Pagination::page()->setMaxLimit(100));
}
```

When pagination is enabled, the framework automatically handles the `page`, `limit`, `offset`, or `cursor` query parameters and includes them in the OpenAPI documentation. See the [Pagination](/http/pagination) guide for more details.

## Resource Routes

For CRUD endpoints against an `AbstractResource`, use `Route::resource()` to build a route pre-configured for one of the five resource modes. It derives the URL, HTTP method, and default configuration from the resource:

```php theme={null}
use apivalk\apivalk\Resource\AbstractResource;
use apivalk\apivalk\Router\Route\Route;
use App\Resource\AnimalResource;

public static function getRoute(): Route
{
    return Route::resource(new AnimalResource(), AbstractResource::MODE_LIST);
}
```

In practice you won't call `Route::resource()` yourself — `AbstractResourceController::getRoute()` does it for you. See [Resources](/resources/index).

## Filtering

You can define which fields are allowed for filtering by using the `filtering()` method. This takes an array of `FilterInterface` instances:

```php theme={null}
use apivalk\apivalk\Router\Route\Filter\StringFilter;
use apivalk\apivalk\Router\Route\Filter\EnumFilter;
use apivalk\apivalk\Router\Route\Filter\DateFilter;
use apivalk\apivalk\Documentation\Property\StringProperty;
use apivalk\apivalk\Documentation\Property\EnumProperty;
use apivalk\apivalk\Documentation\Property\DateProperty;

public static function getRoute(): Route
{
    return Route::get('/v1/users')
                  ->description('List users')
                  ->filtering([
                      EnumFilter::equals(new EnumProperty('status', 'Filter by status', ['active', 'inactive'])),
                      StringFilter::in(new StringProperty('type', 'Filter by type (in)')),
                      DateFilter::greaterThan(new DateProperty('created_at', 'Filter by creation date (greater than)'))
                  ]);
}
```

The `filtering()` method also defines the **allowed filters** for the route. Only configured filters will be automatically resolved from the query string and documented in OpenAPI. See the [Filtering](/http/filtering) guide for more details.
