Type-hint a string-backed enum (Pure Enums and Backed Enums) and the route accepts only its values; anything else is a 404 before your code runs. Explicit binding with Route::bind() in AppServiceProvider::boot() takes over resolution for one parameter name, here a case-insensitive SKU:
enum OrderStatus: string { case Pending = 'pending'; case Paid = 'paid'; case Shipped = 'shipped'; }
Route::get('/orders/status/{status}', function (OrderStatus $status) {
return Order::where('status', $status)->pluck('id');
});
// In AppServiceProvider::boot()
Route::bind('sku', fn (string $value) => Product::where('sku', strtoupper($value))
->firstOrFail());
Route::get('/sku/{sku}', fn (Product $sku) => "{$sku->sku}: {$sku->name}");Output
$ curl -s http://127.0.0.1:8303/orders/status/paid
[1,3]
$ curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8303/orders/status/refunded
404
$ curl -s http://127.0.0.1:8303/sku/bk-2001
BK-2001: DuneRoute::model('sku', Product::class) is the short form that only fixes the class. To change the lookup for every route that binds a model, override resolveRouteBinding($value, $field) on the model, for example to hide unpublished products from the public site.