Laravel

Lesson 01

Routing and controller boundaries

Keep Laravel route files focused on URL wiring and let controllers hand request work to application services.

Good Code

app/Http/Controllers/ReviewController.php
<?php

namespace App\Http\Controllers;

use App\Http\Requests\StoreReviewRequest;
use App\Services\ReviewService;
use Illuminate\Http\JsonResponse;

final class ReviewController
{
    public function __construct(private ReviewService $reviews) {}

    public function store(StoreReviewRequest $request): JsonResponse
    {
        // Controller maps HTTP input to an application service call.
        $review = $this->reviews->create($request->user(), $request->validated());

        return response()->json($review, 201);
    }
}

Bad Code

routes/web.php
<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Route;

Route::post('/reviews', function (Request $request) {
    // The route closure owns validation, persistence, and response shape.
    $data = $request->validate(['title' => 'required', 'body' => 'required']);

    $id = DB::table('reviews')->insertGetId([
        ...$data,
        'user_id' => $request->user()->id,
    ]);

    return ['id' => $id, ...$data];
});

Review Notes

What to review

Good Code

The good version makes the route and controller boundary easy to scan: HTTP data is validated elsewhere, the user and input are passed to a service, and the response status is explicit.

Bad Code

The bad version puts too much behavior in the route file. A reviewer has to audit validation, database writes, ownership, and response shape in the same closure.

Takeaways

  • Routes should describe how HTTP enters the app while controllers and services own the work behind that route.