skip to content

In Laravel, which routes does Route::resource('books', BookController::class) register, with their HTTP verbs, URIs, actions and route names?

level: juniorimportance: must knowfreq 75%

answer

  1. seven conventional actions
  2. index, create, store, show, edit, update, destroy
  3. {book}: singular of the resource name
  4. update answers both PUT and PATCH
  5. names like books.show

basics

~10 s

Route::resource('books', ...) registers seven routes: GET /books (index), GET /books/create (create), POST /books (store), GET /books/{book} (show), GET /books/{book}/edit (edit), PUT/PATCH /books/{book} (update) and DELETE /books/{book} (destroy), named books.index and so on.

solid answer

~30 s

`Route::resource('books', BookController::class)` is shorthand for seven conventional CRUD routes on one controller: `GET /books` → `index`, `GET /books/create` → `create`, `POST /books` → `store`, `GET /books/{book}` → `show`, `GET /books/{book}/edit` → `edit`, `PUT|PATCH /books/{book}` → `update`, and `DELETE /books/{book}` → `destroy`. Each route is named `books.<action>`, and the parameter `{book}` is the singular of the resource name, so a `show(Book $book)` signature gets route model binding. `create` and `edit` exist to serve HTML forms. `php artisan make:controller BookController --resource` stubs all seven methods, and adding `--model=Book` type-hints the model in them.

code

php · 9 lines
php
<?php

use App\Http\Controllers\BookController;
use Illuminate\Support\Facades\Route;

Route::get('/books/popular', [BookController::class, 'popular'])
    ->name('books.popular');

Route::resource('books', BookController::class);

go deeper

for a junior

Recite the seven actions with verbs, URIs and names, and know which ones render forms.

for a middle

Explain the singular parameter name, PUT/PATCH on update, method spoofing, and why custom routes must precede the resource.

for a senior

Use route:list to audit what a resource exposes, trim unused actions, and keep controllers from growing beyond the convention.

for a principal

Decide when CRUD resources fit the domain and when task-shaped endpoints serve clients better, and keep that choice consistent across teams.

## What a resource route is In Laravel, a **resource** is a collection of records exposed over HTTP, like the books in a library catalogue. `Route::resource()` registers the conventional **create, read, update, delete** (CRUD) routes for that resource and points them at one **resource controller**, so one line replaces seven route definitions. ```php Route::resource('books', BookController::class); ``` ## The seven routes | Verb | URI | Action | Route name | |---|---|---|---| | GET | `/books` | `index` | `books.index` | | GET | `/books/create` | `create` | `books.create` | | POST | `/books` | `store` | `books.store` | | GET | `/books/{book}` | `show` | `books.show` | | GET | `/books/{book}/edit` | `edit` | `books.edit` | | PUT/PATCH | `/books/{book}` | `update` | `books.update` | | DELETE | `/books/{book}` | `destroy` | `books.destroy` | Things to notice: - **`create` and `edit` render forms**; `store` and `update` receive them. An API has no use for the form pages, which is what `apiResource` drops. - **`update` matches both PUT and PATCH**, registered as one route. - **The parameter name** is the singular of the resource name (`books` → `{book}`), and hyphens become underscores (`audio-books` → `{audio_book}`). Type-hinting `Book $book` in the action triggers implicit route model binding because the names match. - **HTML forms** can only send GET and POST, so Blade forms for update and destroy send POST with a hidden `_method` field (`@method('PUT')`, `@method('DELETE')`). ## Registration order matters The registrar adds the routes in the order index, create, store, show, edit, update, destroy. `GET /books/create` is registered **before** `GET /books/{book}`, so the literal `create` segment wins instead of being treated as a book id. The same first-match rule is the classic trap when you add your own actions. Laravel matches routes in registration order, so this fails: ```php Route::resource('books', BookController::class); Route::get('/books/popular', [BookController::class, 'popular']); // never reached ``` `GET /books/popular` matches `books/{book}` first and calls `show` with `popular` as the key, which usually ends in a 404 from model binding. Register supplemental routes **before** the resource, or move them to their own controller. ## Generating the controller | Command | Result | |---|---| | `make:controller BookController --resource` (`-r`) | Seven stubbed methods taking `string $id` | | `make:controller BookController --model=Book --resource` | Methods type-hint `Book $book`; offers to create the model if missing | | `make:controller BookController --model=Book --resource --requests` | Also generates `StoreBookRequest` and `UpdateBookRequest` for `store` and `update` | Running `make:controller` without a name also offers **Resource** in its interactive type menu. ## Registering several at once `Route::resources()` takes an array of name ⇒ controller pairs and calls `resource()` for each, applying the same options to all: ```php Route::resources([ 'books' => BookController::class, 'authors' => AuthorController::class, ]); ``` ## Checking the result 1. Run `php artisan route:list --name=books` to see exactly what was registered. 2. Compare the actions listed with the methods on the controller; a registered route whose method is missing fails only when requested. 3. Remove the routes you do not implement with `only()` or `except()` rather than leaving empty methods behind. ## Common mistakes - **Expecting a `GET /books/{book}/delete` page.** There is no confirmation-page action; deletion is a `DELETE` request to the member URI, usually sent by a small form with a spoofed method. - **Naming the action variable after something else.** `show(Book $item)` does not match `{book}`, so the model from the URL is not bound to it. - **Leaving generator stubs in place.** Every registered route is callable; an empty `destroy()` returns an empty 200 response instead of a clear 404 or 405. - **Registering the same resource twice** in different files: routes with the same verb and URI replace each other silently, so the later registration wins without any warning. ## Why the convention pays off A resource route is a contract that the whole Laravel ecosystem understands: generators, starter kits, packages and new team members all expect `books.index` to list and `books.update` to save. Following it means fewer decisions per feature and route files that read like an index of the application. The convention is valuable because every Laravel developer reads `books.edit` or `PUT /books/{book}` the same way; deviate from it only when the domain really does not fit CRUD.

  • Why must GET /books/popular be registered before Route::resource('books', ...)?
    Laravel returns the first route that matches, in registration order. The resource's `GET books/{book}` accepts any segment, so `popular` is taken as a book key and `show` runs. Registering the custom route first fixes it; a numeric constraint on `{book}` via the resource's `where()` also works.
  • How does the update route accept PUT from an HTML form?
    Browsers send only GET and POST from forms, so the Blade form posts with a hidden `_method` field, written with `@method('PUT')`. Laravel's method spoofing reads it and routes the request to `books.update`, which is registered for both PUT and PATCH.
  • What does make:controller --model=Book --resource change in the generated code?
    Instead of `string $id` parameters, `show`, `edit`, `update` and `destroy` type-hint `Book $book`, so route model binding hands them the loaded model. If `App\Models\Book` does not exist, the command offers to generate it.

saying these in an interview costs you the question

  • Route::resource registers five routes: index, show, store, update and destroy.
  • The update route only answers PATCH requests.
  • Custom routes like /books/popular can go anywhere; Laravel picks the most specific.
  • The route parameter is named {id} unless you configure otherwise.
  • create and store are the same route with different verbs.