Router Service

Basic routing

While routing is handled automatically for the backend controllers and CMS pages define their own URL routes in their page configuration, the router service is useful primarily for defining fixed APIs and end points.

You can define these routes by creating a file named routes.php in a same directory as the plugin registration file. The most basic routes simply accept a URI and a Closure:

Route::get('/', function () {
    return 'Hello World';
});

Route::post('foo/bar', function () {
    return 'Hello World';
});

Route::put('foo/bar', function () {
    //
});

Route::delete('foo/bar', function () {
    //
});

Registering a route for multiple verbs

Sometimes you may need to register a route that responds to multiple HTTP verbs. You may do so using the match method on the Route facade:

Route::match(['get', 'post'], '/', function () {
    return 'Hello World';
});

You may even register a route that responds to all HTTP verbs using the any method:

Route::any('foo', function () {
    return 'Hello World';
});

Generating URLs to routes

You may generate URLs to your routes using the Url facade:

$url = Url::to('foo');

Route parameters

Required parameters

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:

Route::get('user/{id}', function ($id) {
    return 'User '.$id;
});

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

Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) {
    //
});

Route parameters are always encased within singular curly brackets. 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.

Optional parameters

Occasionally you may need to specify a route parameter, but make the presence of that route parameter optional. You may do so by placing a ? mark after the parameter name:

Route::get('user/{name?}', function ($name = null) {
    return $name;
});

Route::get('user/{name?}', function ($name = 'John') {
    return $name;
});

Regular expression constraints

You may constrain the format of your route parameters using the where method on a route instance. The where method accepts the name of the parameter and a regular expression defining how the parameter should be constrained:

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

Route::get('user/{id}', function ($id) {
    //
})->where('id', '[0-9]+');

Route::get('user/{id}/{name}', function ($id, $name) {
    //
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);

Named routes

Named routes allow you to conveniently generate URLs or redirects for a specific route. You may specify a name for a route using the as array key when defining the route:

Route::get('user/profile', ['as' => 'profile', function () {
    //
}]);

Route groups & named routes

If you are using route groups, you may specify an as keyword in the route group attribute array, allowing you to set a common route name prefix for all routes within the group:

Route::group(['as' => 'admin::'], function () {
    Route::get('dashboard', ['as' => 'dashboard', function () {
        // Route named "admin::dashboard"
    }]);
});

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 Url::route method:

$url = Url::route('profile');

$redirect = Response::redirect()->route('profile');

If the route defines parameters, you may pass the parameters as the second argument to the route method. The given parameters will automatically be inserted into the URL:

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

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

Route groups

Route groups allow you to share route attributes 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 Route::group method.

Sub-domain routing

Route groups may also be used to route wildcard sub-domains. Sub-domains may be assigned route parameters just like route URIs, allowing you to capture a portion of the sub-domain for usage in your route or controller. The sub-domain may be specified using the domain key on the group attribute array:

Route::group(['domain' => '{account}.example.com'], function () {
    Route::get('user/{id}', function ($account, $id) {
        //
    });
});

Route prefixes

The prefix group array 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:

Route::group(['prefix' => 'admin'], function () {
    Route::get('users', function () {
        // Matches The "/admin/users" URL
    });
});

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

Route::group(['prefix' => 'accounts/{account_id}'], function () {
    Route::get('detail', function ($account_id) {
        // Matches The accounts/{account_id}/detail URL
    });
});

Route Middleware

Registering middleware inside your plugin's boot() method will register it globally for each request. If you want to register middleware to one route at a time you should do it like this:

Route::get('info', 'Acme\News@info')->middleware('Path\To\Your\Middleware');

For route groups it could be done like this:

Route::group(['middleware' => 'Path\To\Your\Middleware'], function () {
    Route::get('info', 'Acme\News@info');
});

If you want to assign a group of middleware to just one route you can do it like this:

Route::middleware(['Path\To\Your\Middleware'])->group(function () {
    Route::get('info', 'Acme\News@info');
});

And finally, if you want to remove middleware from a route you can do it like this:

Route::withoutMiddleware(\Path\To\Removed\Middleware::class)
    ->get('info', 'Acme\News@info');

You can of course add more than one middleware in a group, just one is used in the above examples for convenience.

Throttle middleware

When using Winter's api middleware, you can remove the default rate limiting of 60 requests per minute and replace it with your own by using the below example:

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;

RateLimiter::for("infoThrottle", function (Request $request) {
    return Limit::perMinute(120);
});

Route::group(
    [
        "prefix" => "api",
        "middleware" => ["api"],
    ],
    function () {
        Route::withoutMiddleware("throttle:60,1")
            ->middleware("throttle:infoThrottle")
            ->get('info', 'Acme\News@info');
    }
);

Throwing 404 errors

There are two ways to manually trigger a 404 error from a route. First, you may use the abort helper. The abort helper simply throws a Symfony\Component\HttpFoundation\Exception\HttpException with the specified status code:

App::abort(404);

Secondly, you may manually throw an instance of Symfony\Component\HttpKernel\Exception\NotFoundHttpException.

More information on handling 404 exceptions and using custom responses for these errors may be found in the errors & logging section of the documentation.

Copyright © 2024 Winter CMS