Routes
withRouting() mounts a layer's route files the way Application::configure()->withRouting() does in bootstrap/app.php. Call it from the layer provider's boot() method:
public function boot(): void
{
$this->withRouting(
web: __DIR__ . '/../../routes/web.php',
api: __DIR__ . '/../../routes/api.php',
commands: __DIR__ . '/../../routes/console.php',
channels: __DIR__ . '/../../routes/channels.php',
health: '/orders/up',
);
}
| Argument | Behaviour |
|---|---|
web | Loaded in the web middleware group. A path or an array of paths. |
api | Loaded in the api middleware group, under the apiPrefix prefix. A path or an array of paths. |
commands | Required when the application runs in the console. |
channels | Required on every request. |
health | Registers a GET route at this URI that returns {"status":"ok"}. |
apiPrefix | Prefix of the api routes. Defaults to api. |
Every argument is optional, and missing files are skipped. The provider generated by osdd:layer calls withRouting() with the four standard files, so a layer gets its routes as soon as you create them.
Route files
The routes generator of osdd:layer creates the four files when you create the layer:
php artisan osdd:layer functional/orders --generators=provider,routes
For an existing layer, create the files by hand. osdd:layer refuses a layer that already exists, and with --force it rewrites the provider and the route files you already have.
use Functional\Orders\Http\Controllers\OrderController;
use Illuminate\Support\Facades\Route;
Route::resource('orders', OrderController::class);
use Functional\Orders\Http\Controllers\Api\OrderController;
use Illuminate\Support\Facades\Route;
Route::get('orders', [OrderController::class, 'index']); // GET /api/orders
Do not add an api prefix inside routes/api.php: withRouting() already adds it.
Console routes and schedules
A layer's routes/console.php works like the application's one. Define closure commands and schedules in it:
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Schedule;
Artisan::command('orders:report', function () {
$this->info('Orders report sent.');
});
Schedule::command('orders:prune-abandoned')->daily();
php artisan schedule:list shows the schedules of every layer.
Broadcast channels
use Functional\Orders\Models\Order;
use Illuminate\Support\Facades\Broadcast;
Broadcast::channel('orders.{order}', function ($user, Order $order) {
return $user->id === $order->user_id;
});
Route caching
When routes are cached (php artisan route:cache or php artisan optimize), the web, api and health routes of every layer come from the route cache: withRouting() does not load them again. The commands and channels files are still loaded, as Laravel's own withRouting() does, so the closure commands, schedules and broadcast channels of each layer keep working.
Run php artisan route:cache again after changing a layer's web.php or api.php.
Custom routes
For anything beyond these conventions, such as a domain, a name prefix or a custom middleware group, use the Route facade in boot():
use Illuminate\Support\Facades\Route;
public function boot(): void
{
Route::middleware(['web', 'auth'])
->prefix('admin/orders')
->name('admin.orders.')
->group(__DIR__ . '/../../routes/admin.php');
}
Wrap these calls in if (! $this->app->routesAreCached()) to skip them once routes are cached.