skip to content

Route Files & Verbs

Routes live in routes/web.php and the opt-in routes/api.php, registered with verb methods, view and redirect shortcuts, and a fallback. Interviewers check what prefix and group each file gets.

on this pageshow

explore

questions

6

In Laravel, which HTTP verbs do Route::get, Route::match and Route::any register, and how do you confirm them?

level: juniorimportance: must knowfreq 60%

answer

  1. one router method per verb
  2. get also answers HEAD
  3. match takes a list of verbs
  4. any: all seven router verbs
  5. route:list shows GET|HEAD, -v adds middleware

basics

~20 s

Route::get registers GET and HEAD; post, put, patch, delete and options register one verb each; Route::match registers the verbs you list (plus HEAD when GET is listed); Route::any registers all seven router verbs. php artisan route:list shows each route's verbs, URI, name and action.

solid answer

~40 s

Laravel's router has one method per verb: `Route::get`, `post`, `put`, `patch`, `delete` and `options`. `Route::get` is special: it registers **GET and HEAD**, so HEAD requests work for free. `Route::match(['get', 'post'], '/search', ...)` registers the verbs you list (Laravel adds HEAD to any route that has GET), and `Route::any` registers all seven verbs the router knows (GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS). A request whose URI matches but whose verb does not gets a 405 Method Not Allowed. To confirm what you registered, run `php artisan route:list`: it prints `GET|HEAD`, `POST` or `ANY` per route, `-v` adds middleware, and `--method=`, `--path=` and `--name=` filter the list.

code

bash · 7 lines
bash
php artisan route:list --path=recipes

# with middleware per route
php artisan route:list --path=recipes -v

# only POST routes, in registration order
php artisan route:list --method=POST --sort=definition

go deeper

for a junior

Know the verb methods, that Route::get also registers HEAD, and that route:list shows what you registered.

for a middle

Explain match versus any, why a wrong verb produces 405 rather than 404, and which route:list options filter and expand the output.

for a senior

Push back on any() in reviews, keep one route per verb and URI, and use route:list --json or --method in CI to catch accidental write routes.

for a principal

Set conventions for verb use across teams so APIs stay predictable, and decide where route inventories are checked automatically.

## One method per verb Laravel's router (the `Route` facade resolves `Illuminate\Routing\Router`) exposes a registration method for each HTTP verb. Every one takes a URI and an **action**: a closure, a `[Controller::class, 'method']` array, or an invokable controller class. | Call | Verbs registered | Typical use | |---|---|---| | `Route::get($uri, $action)` | GET, HEAD | pages, reads | | `Route::post(...)` | POST | form submissions, creates | | `Route::put(...)` / `Route::patch(...)` | PUT / PATCH | full / partial updates | | `Route::delete(...)` | DELETE | removals | | `Route::options(...)` | OPTIONS | rarely written by hand | | `Route::match(['get', 'post'], ...)` | the listed verbs, plus HEAD when GET is listed | a search form that also accepts a GET link | | `Route::any(...)` | GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS | proxies, catch-all handlers | The seven verbs in the last row are the router's static `Router::$verbs` list; `Route::any` registers exactly that list. `Route::match` upper-cases whatever you pass, so `['get', 'post']` and `['GET', 'POST']` are equivalent. The `Route` constructor also appends **HEAD** to any route whose verbs include GET, whichever registration method created it. ## Why GET also answers HEAD A **HEAD** request asks for the headers a GET would return, without the body. Monitoring tools and some crawlers use it. Because `Route::get` registers both verbs (and the `Route` constructor adds HEAD to any GET route anyway), a recipe page defined with `Route::get('/recipes/{slug}', ...)` answers HEAD without extra code, and `route:list` shows the route as `GET|HEAD`. ## What happens when the verb does not match When the path matches a route but no route for the request's verb exists, Laravel does not return 404. It throws a **`MethodNotAllowedHttpException`** (405) with a message such as `The POST method is not supported for route recipes. Supported methods: GET, HEAD.` Two details follow from the router's source: - An **OPTIONS** request to a URI that has routes for other verbs gets an automatic `200` response whose `Allow` header lists those verbs, even though you never registered an OPTIONS route. - The 405 message is the fastest clue that a form or client is using the wrong verb (see method spoofing for HTML forms). ## Prefer explicit verbs over any and match - **`Route::any` widens the attack surface.** A read-only page registered with `any` also accepts POST, PUT and DELETE, so writes can land on a handler that never expected them. - **Overlapping definitions are ambiguous.** The router keys routes by verb and URI, so `Route::get('/menu', A)` plus `Route::any('/menu', B)` leaves two definitions competing for GET. Which one wins depends on registration details, so keep one route per verb and URI. - **`Route::match` is the honest middle ground** when one handler genuinely serves two verbs, such as a search endpoint reachable by a GET link and a POST form. ## Confirming the result with route:list `php artisan route:list` prints every registered route. Useful options, all defined in the framework's `RouteListCommand`: 1. `-v` adds each route's middleware; `-vv` expands middleware groups into their members. 2. `--method=POST`, `--path=api`, `--name=recipes` and `--domain=` filter the list. 3. `--except-vendor` hides package routes; `--only-vendor` shows only them. 4. `--sort=definition` lists routes in registration order instead of the default sort by URI; `-r` reverses. 5. `--json` prints machine-readable output for scripts and CI checks. In the method column, a route registered with `Route::any` (or `Route::redirect`, which uses `any` internally) is shown as `ANY`. ## Reading a 405 in an interview Interviewers like to paste the error text and ask what went wrong. The message names the verb the router saw and the verbs it would have accepted, so it answers most questions on its own: - **POST not supported, supported GET, HEAD**: a form or client is posting to a read-only URL; either the route should be `Route::post` or the client is wrong. - **GET not supported, supported POST**: someone opened a form-handling URL in the browser address bar, or a plain link points at it. - **POST not supported, supported PUT, PATCH or DELETE**: an HTML form is missing its method-spoofing field. In every case `route:list --path=...` confirms which verbs the URI really has. ## A worked example on a recipe site ```php use App\Http\Controllers\RecipeController; use Illuminate\Support\Facades\Route; Route::get('/recipes', [RecipeController::class, 'index']); Route::post('/recipes', [RecipeController::class, 'store']); Route::match(['get', 'post'], '/recipes/search', [RecipeController::class, 'search']); ``` Running `php artisan route:list --path=recipes` shows `GET|HEAD recipes`, `POST recipes` and `GET|POST|HEAD recipes/search` (HEAD is appended after the verbs you listed). A PATCH to `/recipes` gets a 405, not a 404, because the URI exists for other verbs.

  • What does a Laravel app return for an OPTIONS request to a URI that only has GET and POST routes?
    The router finds routes for other verbs on that URI and, because the request is OPTIONS, answers with a `200` and an `Allow` header listing them (for example `GET,HEAD,POST`). For any other unmatched verb it throws `MethodNotAllowedHttpException`, a 405. CORS preflight handling is a separate concern of the CORS middleware.
  • Why is Route::any a poor default for a page that only reads data?
    It registers all seven verbs, so the same handler also accepts POST, PUT, PATCH and DELETE. Clients that send the wrong verb get a normal response instead of a 405 that would expose their bug, and a read-only handler may end up processing writes it was never designed to validate.

saying these in an interview costs you the question

  • Route::get answers only GET, so HEAD requests fail
  • Route::any is a clean way to serve a form and its submission
  • A wrong verb on an existing URI returns 404
  • route:list shows each route's middleware without extra flags
  • Two routes for the same verb and URI both run in order
open as a page

In a Laravel 13 app, how do routes/web.php and routes/api.php differ, and why does a new app have no api.php?

level: juniorimportance: must knowfreq 70%

basics

~10 s

routes/web.php is loaded inside the web middleware group for browser pages with sessions and CSRF protection; routes/api.php, created by php artisan install:api, is loaded inside the stateless api group under an automatic /api prefix.

open as a page

In Laravel, what do Route::view and Route::redirect register, and what defaults and reserved parameter names do they carry?

level: juniorimportance: should knowfreq 35%

basics

~10 s

Route::view registers a GET/HEAD route that renders a Blade view with optional data; Route::redirect registers a route for every verb that redirects with 302 unless you pass a status; Route::permanentRedirect sends 301.

open as a page

In Laravel, what does Route::fallback() do, where should you define it, and what are its limits?

level: middleimportance: should knowfreq 35%

basics

~20 s

Route::fallback() registers a GET/HEAD route that runs only when no other route matches; defined in routes/web.php it gets the web middleware group, it is checked last wherever it is declared, and its response status is whatever the action returns.

open as a page

In a Laravel Blade form, why do you add @method('DELETE'), and what breaks when that spoofing is set up wrong?

level: middleimportance: should knowfreq 50%

basics

~20 s

HTML forms can only send GET or POST, so @method('DELETE') adds a hidden _method field; Laravel reads it on a POST request and routes the request as DELETE, which lets a form reach a Route::delete route.

open as a page

In Laravel 13's bootstrap/app.php, how do you register an extra route file, and how do withRouting's then and using arguments differ?

level: seniorimportance: nice to knowfreq 25%

basics

~20 s

Pass extra files to withRouting's web: or api: arrays, or register them in a then: closure that runs after the default files; a using: closure replaces the framework's registration entirely, so web:, api: and health: are no longer registered for you.

open as a page