DEV
Accueil À propos Services Projets Blog Contact
Recruter
Laravel & PHP

Créer une API REST robuste avec Laravel : le guide complet

🇬🇧 Read in English
Créer une API REST robuste avec Laravel : le guide complet

Il y a trois ans, j'ai rejoint une startup qui utilisait Laravel pour son backend. Mon premier ticket : "ajoute un endpoint pour récupérer les commandes d'un utilisateur". Simple, non ? Deux jours plus tard, l'API était en production… et complètement en vrac. N+1 queries partout, aucune authentification sur les routes, réponses JSON incohérentes selon l'endpoint. Un désastre silencieux.

Depuis, j'ai construit des dizaines d'APIs avec Laravel. J'ai appris de mes erreurs, souvent douloureusement. Voici le guide que j'aurais voulu avoir à l'époque.

Pourquoi Laravel est parfait pour les APIs REST

Laravel n'est pas juste un framework web. C'est une plateforme complète qui intègre nativement tout ce dont vous avez besoin pour une API professionnelle et maintenable :

  • Sanctum — authentification par tokens sans configuration complexe
  • API Resources — transformez vos modèles Eloquent en JSON propre
  • Form Requests — validation centralisée hors des contrôleurs
  • Rate Limiting — protection intégrée dans les définitions de routes
  • Queues & Events — traitements asynchrones pour ne pas bloquer les réponses

Et ce n'est pas que du marketing. Chacune de ces fonctionnalités peut vous éviter des heures de débogage.

Structure de projet : pensez dès le départ à la scalabilité

La première chose à faire avant d'écrire une ligne de code : versionner votre API. Même si vous n'avez qu'une seule version aujourd'hui, vous serez reconnaissant de l'avoir fait dans six mois quand vous devrez introduire des changements breaking sans casser les clients existants.

app/
├── Http/
│   ├── Controllers/Api/V1/
│   │   ├── AuthController.php
│   │   ├── UserController.php
│   │   └── PostController.php
│   ├── Requests/Api/V1/
│   │   ├── LoginRequest.php
│   │   └── StorePostRequest.php
│   └── Resources/Api/V1/
│       ├── UserResource.php
│       └── PostResource.php

Authentification avec Laravel Sanctum

Sanctum est la solution officielle pour sécuriser vos APIs Laravel. Pas de JWT à configurer manuellement, pas de bibliothèques tierces compliquées. Installez-le en trois commandes :

composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate

Ajoutez le trait HasApiTokens à votre modèle User :

use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
}

Voici un contrôleur d'authentification complet, avec gestion des erreurs :

class AuthController extends Controller
{
    public function login(LoginRequest $request): JsonResponse
    {
        $user = User::where('email', $request->email)->first();

        if (!$user || !Hash::check($request->password, $user->password)) {
            return response()->json(['message' => 'Identifiants incorrects.'], 401);
        }

        // Token avec expiration à 30 jours
        $token = $user->createToken('api-token', ['*'], now()->addDays(30))->plainTextToken;

        return response()->json([
            'token'   => $token,
            'expires' => now()->addDays(30)->toIso8601String(),
            'user'    => new UserResource($user),
        ]);
    }

    public function logout(): JsonResponse
    {
        auth()->user()->currentAccessToken()->delete();
        return response()->json(['message' => 'Déconnecté avec succès.']);
    }
}

API Resources : exposez uniquement ce qu'il faut

C'est probablement la fonctionnalité la plus sous-utilisée par les développeurs juniors  et la plus importante. Une API Resource contrôle exactement ce que vous envoyez au client, évitant d'exposer des champs sensibles par inadvertance.

class UserResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id'         => $this->id,
            'name'       => $this->name,
            'email'      => $this->email,
            'role'       => $this->role,
            'avatar_url' => $this->avatar_url,
            'created_at' => $this->created_at->toIso8601String(),
            // Jamais : 'password', 'remember_token'...
        ];
    }
}

Validation avec Form Requests : sortez ça des contrôleurs

Règle absolue : ne validez jamais directement dans vos contrôleurs. Votre contrôleur doit faire une seule chose — orchestrer la réponse. La validation appartient à une Form Request dédiée :

class StorePostRequest extends FormRequest
{
    public function authorize(): bool { return true; }

    public function rules(): array
    {
        return [
            'title'       => ['required', 'string', 'max:255'],
            'content'     => ['required', 'string', 'min:100'],
            'category_id' => ['required', 'exists:categories,id'],
            'tags'        => ['nullable', 'array'],
            'tags.*'      => ['exists:tags,id'],
        ];
    }

    public function messages(): array
    {
        return [
            'title.required'     => 'Le titre est obligatoire.',
            'content.min'        => 'Le contenu doit faire au moins 100 caractères.',
            'category_id.exists' => 'Cette catégorie n\'existe pas.',
        ];
    }
}

Gestion des erreurs : la cohérence avant tout

Une bonne API retourne des erreurs structurées et prévisibles. Vos clients , qu'il s'agisse d'une app mobile ou d'un frontend React doivent pouvoir gérer les erreurs de manière uniforme. Dans bootstrap/app.php (Laravel 11), configurez le gestionnaire d'exceptions globalement :

->withExceptions(function (Exceptions $exceptions) {
    $exceptions->render(function (ModelNotFoundException $e, Request $request) {
        if ($request->is('api/*')) {
            return response()->json(['message' => 'Ressource introuvable.', 'error' => 'not_found'], 404);
        }
    });

    $exceptions->render(function (ValidationException $e, Request $request) {
        if ($request->is('api/*')) {
            return response()->json([
                'message' => 'Données invalides.',
                'errors'  => $e->errors(),
            ], 422);
        }
    });
})

Rate Limiting : protégez votre API des abus

Sans rate limiting, n'importe qui peut spammer vos endpoints et faire tomber votre serveur. Laravel le rend trivial :

// routes/api.php
Route::middleware(['auth:sanctum', 'throttle:api'])->group(function () {
    Route::apiResource('posts', PostController::class);
});

// Limite stricte sur le login pour éviter le brute-force
Route::middleware('throttle:5,1')->post('/login', [AuthController::class, 'login']);

Éliminer les N+1 queries avec Eager Loading

Une des erreurs les plus fréquentes en API Laravel : récupérer des collections sans charger les relations à l'avance. Résultat : 1 query pour la liste + 1 query par élément pour charger la relation = N+1 queries.

// ❌ N+1 queries : catastrophe en production
$posts = Post::all(); // 1 query
foreach ($posts as $post) {
    echo $post->author->name; // 1 query PAR post
}

// ✅ Eager loading : 2 queries, toujours
$posts = Post::with(['author', 'category', 'tags'])->paginate(20);

Conclusion : les 3 règles d'or d'une bonne API

Après des années à construire des APIs avec Laravel, voici ce qui fait vraiment la différence :

  1. Versionner dès le premier jour : même si vous n'avez qu'une seule version. C'est trivial à faire au départ, douloureux à ajouter plus tard.
  2. Réponses cohérentes : même structure JSON pour tous les succès, même structure pour toutes les erreurs. Vos frontend developers vous remercieront.
  3. Documenter automatiquement : utilisez Scramble ou L5-Swagger. Une API non documentée est une API inutilisable.

L'API que vous construisez aujourd'hui, d'autres personnes vont l'utiliser demain. Autant leur rendre la vie facile y compris votre futur vous.

Articles similaires

Écrire sur WhatsApp