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.
Route::get('/items/approved', [ItemController::class, 'approved']);
Route::get('/items/{id}', [ItemController::class, 'show']);
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
Route::get('/items/approved', function(){
return 'Item approved';
});
Route::get('/items/{id}',function(){
return 'Item id';
})->where('id', '[0-9]+');