Your next chapter / Trace a request through Laravel

Foundation · 45 MINUTES · VERSION 1

Trace a request through Laravel

Separate bootstrap, routes, middleware, controllers, and responses. Run a focused Laravel router lab without changing application data.

Reviewed 23 Oct 2026

Your setup may differ. Windows, Ubuntu, and optional tool bundles →

Log in or create an account to keep private notes, bookmarks, and learning progress. Reading is free without an account.

What you will learn

  • Explain the main steps between a browser request and a Laravel response.
  • Identify the different jobs of a route, middleware, and controller.
  • Run a small request through Laravel's router without touching a database.

Theory: from browser to response

A browser sends a request with a method, a target URL, headers, and sometimes a body. DNS helps find a server address, and HTTPS protects transport. The web server passes an application request to PHP. In a normal Laravel deployment, the public entry point is public/index.php. Only the public directory should be exposed by the web server.

Laravel loads Composer's autoloader and bootstraps the application. The application prepares its services. Middleware can inspect the request before the selected route runs. A route matches a method and path. It can call a controller, which handles that action and returns a response. The response travels back through middleware and then to the client. Some middleware can return early, such as denying a request before a controller runs.

Browser → web server/PHP → Laravel bootstrap → middleware
        → matching route/controller → response → middleware → browser

A controller does not have to use a database. It can return a page, JSON, a redirect, or an error. A route name is an internal label used to generate links; it is different from the URL path. A query string carries extra request values, such as ?status=done. Never assume that a query value is valid just because it came from a link.

Worked example: observe the router

Required: a local Laravel 13 project with its Composer dependencies installed and a compatible PHP runtime (this project uses PHP 8.4). Use a disposable practice project or this site's source checkout. Do not change a company production application.

Save the following as request_trace.php in that project's root, beside composer.json. Run commands from that same root. This is a standalone CLI experiment using Laravel components. It does not boot the full application, register permanent web routes, load your .env, or write to the database. The complete lifecycle above contains more steps than this focused router experiment.

<?php

declare(strict_types=1);

// Run from the root of a Laravel project with Composer dependencies installed.
require getcwd().'/vendor/autoload.php';

use Illuminate\Container\Container;
use Illuminate\Events\Dispatcher;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Router;

class LabTraceMiddleware
{
    public function handle(Request $request, Closure $next): mixed
    {
        $response = $next($request);
        $response->headers->set('X-Lesson-Trace', 'checked');

        return $response;
    }
}

class LabTaskController
{
    public function __invoke(Request $request): JsonResponse
    {
        $status = $request->query('status', 'done');
        if (! in_array($status, ['todo', 'done'], true)) {
            return new JsonResponse(['error' => 'Use todo or done.'], 422);
        }

        return new JsonResponse(['status' => $status, 'total' => $status === 'done' ? 2 : 1]);
    }
}

$container = new Container;
$router = new Router(new Dispatcher($container), $container);
$router->get('/study/tasks', LabTaskController::class)
    ->middleware(LabTraceMiddleware::class)->name('study.tasks');
$request = Request::create('/study/tasks?status=done', 'GET');
$container->instance('request', $request);
$container->instance(Request::class, $request);
$response = $router->dispatch($request);

echo 'Route: '.$request->route()->getName().PHP_EOL;
echo 'Middleware: '.$response->headers->get('X-Lesson-Trace').PHP_EOL;
echo 'Status: '.$response->getStatusCode().PHP_EOL;
echo 'Body: '.$response->getContent().PHP_EOL;

Run php request_trace.php from the Laravel project root in Windows PowerShell/Command Prompt or Ubuntu Bash. For this site's tracked copy, use php content/labs/request_trace.php from the repository root. Source code is identical on these systems. No local server or database is needed.

Expected output:

Route: study.tasks
Middleware: checked
Status: 200
Body: {"status":"done","total":2}

The request matches the GET route. Laravel resolves the controller and gives it the Request object. The controller accepts only todo or done. It returns a JSON response with a small fixed example count. Middleware adds a response header after the controller returns. The count is dummy data, not a query of your real tasks.

Guided practice

  1. Run the original file and compare all four lines.
  2. Change ?status=done to ?status=todo. Expect status 200 and body {"status":"todo","total":1}.
  3. Change it to ?status=blocked. Expect status 422 and body {"error":"Use todo or done."}. The middleware header still says checked.
  4. Remove the query string. The default status is done, so the original body returns.
  5. In a separate practice Laravel app, inspect public/index.php, bootstrap/app.php, and routes/web.php. Use php artisan route:list --path=lessons in this site to inspect its real lesson routes. Do not copy this standalone router into routes/web.php; normal Laravel apps use the framework's configured routing and middleware.

Independent exercise

Change the example so the allowed status values are todo, done, and blocked. Give blocked a dummy count of zero. Update the validation message. Verify all three valid values and one invalid value. Keep the original GET route name and the middleware response header.

Write a five-step explanation of the request journey. Label which steps your CLI experiment runs and which normal web steps it does not run. You do not need to build DNS, a web server, or a database for this exercise.

Common mistakes

  • Missing vendor/autoload.php: install the practice project's locked Composer dependencies and run from its root. Do not change your global PHP version to guess a fix; inspect the required version first.
  • Confusing study.tasks with /study/tasks: one is a route name; the other is a URL path.
  • Expecting middleware to run only before the controller: code after $next can inspect the response.
  • Trusting query input: validation still belongs on the server.
  • Exposing the project root: a deployed Laravel web server must use the public document root.

Self-check — not graded

  1. What chooses the controller for a method and path?
  2. Does returning JSON require a database query?
  3. Where does the example's response header come from?

Interview practice

“What happens when a request reaches Laravel?” Start at the public entry point, then describe bootstrap, middleware, route/controller, and response. Mention that a denial may return before the controller. Keep DNS and web-server behavior separate from Laravel's own work.

English practice and glossary

  • Request: a client's message asking a server to do something.
  • Response: the server's reply.
  • Route: a mapping from method/path to an action.
  • Middleware: code that can inspect requests and responses around the action.
  • Controller: code responsible for handling an application action.
  • Bootstrap: preparing the application before handling work.

Write: “The request uses GET. The route calls __. I checked the response status and __.” Explain one invalid-input result aloud.

Recap and next step

Routes choose actions, middleware wraps work, and controllers return responses. A full Laravel request includes bootstrap and web infrastructure too. Next, read requests and choose useful HTTP response statuses. Official references and review dates are listed below.

Reveal exercise hints and self-check answers
  1. The router matches the method and path to the registered route action.
  2. No. A controller may return a response without querying data.
  3. LabTraceMiddleware sets it after $next($request) returns the controller's response.

Exercise outline: add blocked to the strict allowed list; choose zero for its count; keep the existing counts for todo and done; update the error text. Check 200 for the three valid values and 422 for an unknown value. A complete explanation says this CLI lab constructs a request directly and does not use a real browser, DNS, web server, full application bootstrap, or database.

Official references

Practise on your own computer. The exercise self-checks are not graded. This version also has a scored quiz for verified accounts. Signed-in learners can save reading, self-reported practice, private notes, and bookmarks.