A segment in braces captures part of the URI and reaches the closure by position, after injected services such as Request. A ? makes it optional, with a default on the argument. It matches anything but / until constrained by where() or the helpers whereNumber, whereAlpha, whereAlphaNumeric, whereUuid, whereUlid and whereIn.
Route::get('/orders/{id}', fn (string $id) => "Order #{$id}")->whereNumber('id');
Route::get('/catalog/{page?}', fn (int $page = 1) => "Catalog page {$page}")
->whereNumber('page');
Route::get('/isbn/{isbn}', fn (string $isbn) => "ISBN {$isbn}")
->where('isbn', '97[89][0-9]{10}');
Route::get('/formats/{format}', fn (string $format) => "Format: {$format}")
->whereIn('format', ['hardcover', 'paperback', 'ebook']);Output
$ for p in orders/42 orders/abc catalog catalog/7 isbn/9781492057611 isbn/12345 \
formats/ebook formats/vinyl; do
echo "$p -> $(curl -s -o /tmp/b -w '%{http_code}' http://127.0.0.1:8303/$p) $(head -c 80
/tmp/b)"
done
orders/42 -> 200 Order #42
orders/abc -> 404 {"message":"No such page."}
catalog -> 200 Catalog page 1
catalog/7 -> 200 Catalog page 7
isbn/9781492057611 -> 200 ISBN 9781492057611
isbn/12345 -> 404 {"message":"No such page."}
formats/ebook -> 200 Format: ebook
formats/vinyl -> 404 {"message":"No such page."}A failed constraint just means no match, so the fallback route (Special Routes) answered. Omit ^ and $; Symfony 6,093 's route compiler embeds each pattern. Route::pattern('id', '[0-9]+') in AppServiceProvider applies a rule globally, and ->where('terms', '.*') lets a last segment contain slashes.