I’m learning Laravel on an existing 11.29.0
project.
I have two routes defined:
//api.php
Route::get('/items/approved', [ItemController::class, 'approved']);
Route::get('/items/{id}', [ItemController::class, 'show']);
In my controller I have this:
//ItemController.php
namespace AppHttpControllers;
use IlluminateHttpResourcesJsonAnonymousResourceCollection;
use AppHttpResourcesItemResource;
class ItemController extends Controller{
//MARK: Approved
public function approved(): AnonymousResourceCollection
{
error_log('inside approved');
//...
}
//MARK: Show
public function show($id): ItemResource|JsonResponse
{
error_log('inside show');
//...
}
}
When I do a GET
request to /items/approved
it always hits the show($id)
function.
Shouldn’t the fact that /items/approved
comes before /items/{id}
make it so the approved()
function is called? What am I missing?
3
Answers
This happens because both the routes are same and Laravel could not make difference between
and
since "approved" and "{id}" are same endpoints.
If you enter same path twice (or more) the last one will replace all the above.
Fix : Just change the route paths like
and
You can see it works as expected!
You can try these
The Reason is laravel is treating both as same, for example if you send a request
http://127.0.0.1:8000/items/approved
http://127.0.0.1:8000/items/1232
Technically it should work as expected but due to laravel wildcard it look for but Laravel interprets {id} in /items/{id} as a wildcard parameter that can match any value, including the string approved. As a result, the /items/{id} route matches the request /items/approved before Laravel has a chance to match it against the /items/approved route.
How to fix:
Laravel routes are evaluated top-down, but more generic routes like {id} can override specific ones if their patterns are not restricted.
The where() method allows you to fine-tune what a route parameter can match.
Example