php artisan make:controller CategoryController writes a class to app/Http/Controllers. Its base class has been empty since Laravel 11 2,157 (the authorization and validation traits were removed), so extending it is optional. Every public method can be an action, and route parameters arrive by name.
public function index(): Collection
{
return Category::withCount('products')->orderBy('name')->get();
}
Route::get('/categories', [CategoryController::class, 'index'])
->middleware('cache.headers:public;max_age=300;etag'); // see Section 5.5.9Output
$ curl -s $B/categories | jq -c '.[]'
{"id":1,"slug":"computing","name":"Computing","products_count":3}
{"id":2,"slug":"fiction","name":"Fiction","products_count":1}Prefer the [Class::class, 'method'] callable to the old 'CategoryController@index' string, which IDEs cannot follow. Keep actions thin: read the request, call a model or service, return a response.