0 XP
?
Intermédiaire65 min45 XP

Objectifs de cette leçon

  • Créer un contrôleur CRUD complet
  • Lier les vues aux contrôleurs
  • Gérer les flash messages et validations

CRUD complet avec une API REST 🔄

Qu'est-ce que le CRUD ?

CRUD = Create, Read, Update, Delete — les 4 opérations fondamentales de toute application qui manipule des données.

OpérationHTTPSQLMéthode du contrôleur
CreatePOSTINSERTstore()
Read (tous)GETSELECTindex()
Read (un)GETSELECT WHEREshow()
UpdatePUT/PATCHUPDATEupdate()
DeleteDELETEDELETEdestroy()

💡 L'API REST expose ces opérations via des URLs et des méthodes HTTP standard. C'est le langage commun du web moderne.


1. READ — Lister les ressources (GET /posts) 📖

// routes/api.php
Route::get('/posts', [PostController::class, 'index']);
class PostController extends Controller
{
    public function index()
    {
        // Récupère TOUS les articles
        $posts = Post::all();

        // Les retourne en JSON
        return response()->json($posts);
    }
}

Requête : GET /api/posts Réponse : 200 OK

[
  { "id": 1, "title": "Article 1", "body": "Contenu..." },
  { "id": 2, "title": "Article 2", "body": "Contenu..." }
]

2. CREATE — Créer une ressource (POST /posts) ➕

Route::post('/posts', [PostController::class, 'store']);
public function store(Request $request)
{
    // 1. Valider les données reçues
    $validated = $request->validate([
        'title' => 'required|string|max:255',
        'body'  => 'required|string',
    ]);

    // 2. Créer l'article
    $post = Post::create($validated);

    // 3. Retourner l'article + code 201 Created
    return response()->json($post, 201);
}

Requête : POST /api/posts

{ "title": "Nouvel article", "body": "Mon contenu" }

Réponse : 201 Created

{ "id": 3, "title": "Nouvel article", "body": "Mon contenu" }

3. READ — Afficher une ressource (GET /posts/{id}) 🔍

Route::get('/posts/{id}', [PostController::class, 'show']);
public function show(string $id)
{
    // findOrFail retourne 404 si l'ID n'existe pas
    $post = Post::findOrFail($id);

    return response()->json($post);
}

Requête : GET /api/posts/1 Réponse : 200 OK

{ "id": 1, "title": "Article 1", "body": "Contenu..." }

⚠️ Si l'ID n'existe pas → 404 Not Found avec un message d'erreur JSON automatique.


4. UPDATE — Modifier une ressource (PUT /posts/{id}) ✏️

Route::put('/posts/{id}', [PostController::class, 'update']);
public function update(Request $request, string $id)
{
    $post = Post::findOrFail($id);

    $validated = $request->validate([
        'title' => 'sometimes|string|max:255',
        'body'  => 'sometimes|string',
    ]);

    $post->update($validated);

    return response()->json($post);
}

Requête : PUT /api/posts/1

{ "title": "Titre modifié" }

Réponse : 200 OK

{ "id": 1, "title": "Titre modifié", "body": "Contenu..." }

💡 Avec sometimes, seuls les champs envoyés sont modifiés. Pratique pour les mises à jour partielles.


5. DELETE — Supprimer une ressource (DELETE /posts/{id}) 🗑️

Route::delete('/posts/{id}', [PostController::class, 'destroy']);
public function destroy(string $id)
{
    $post = Post::findOrFail($id);
    $post->delete();

    // 204 = No Content : la suppression a réussi
    return response()->json(null, 204);
}

Requête : DELETE /api/posts/1 Réponse : 204 No Content (pas de body)


Code complet du contrôleur 🎯

<?php

namespace AppHttpControllers;

use AppModelsPost;
use IlluminateHttpRequest;

class PostController extends Controller
{
    public function index()
    {
        return response()->json(Post::all());
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'title' => 'required|string|max:255',
            'body'  => 'required|string',
        ]);

        $post = Post::create($validated);
        return response()->json($post, 201);
    }

    public function show(string $id)
    {
        return response()->json(Post::findOrFail($id));
    }

    public function update(Request $request, string $id)
    {
        $post = Post::findOrFail($id);

        $validated = $request->validate([
            'title' => 'sometimes|string|max:255',
            'body'  => 'sometimes|string',
        ]);

        $post->update($validated);
        return response()->json($post);
    }

    public function destroy(string $id)
    {
        $post = Post::findOrFail($id);
        $post->delete();
        return response()->json(null, 204);
    }
}

Code HTTP et leur signification

CodeSignificationUsage
200OKGET, PUT réussis
201CreatedPOST réussi (nouvelle ressource)
204No ContentDELETE réussi
400Bad RequestDonnées invalides (hors validation)
404Not FoundRessource inexistante
422Unprocessable EntityÉchec de validation
500Internal Server ErrorErreur serveur

Bonnes pratiques ✅

  1. Toujours valider les entrées avec $request->validate() avant create() ou update()
  2. Utiliser les bons codes HTTP : 201 pour création, 204 pour suppression, 404 si non trouvé
  3. Utiliser Resource::collection() pour formater la réponse (API Resources)
  4. Pagine les listes : Post::paginate(15) plutôt que all() pour les gros volumes
  5. Toujours gérer les erreurs : findOrFail() + try/catch si nécessaire
  6. Documenter l'API avec des annotations PHPDoc ou un outil comme Scribe

Pièges fréquents 🚨

PiègeSolution
❌ Utiliser GET /api/posts/delete/1Utilise DELETE /api/posts/1 (convention REST)
❌ Oublier findOrFail()Sans ça, tu risques une erreur 500 au lieu de 404
❌ Modifier un ID (PUT /api/posts/1 avec id: 2)Ne pas inclure l'ID dans le body, il vient de l'URL
❌ Retourner une erreur sans status codeLaravel le fait automatiquement avec findOrFail()
❌ Créer sans validationLes données invalides corrompent la BDD

Exercices pour toi 🎯

  1. Pratique : Crée un contrôleur ProductController complet avec les 5 méthodes CRUD.
  2. Routes : Enregistre les 5 routes REST pour /api/products.
  3. Validation : Ajoute une validation avec title requis, price numérique requis, stock entier optionnel.
  4. Test : Utilise php artisan route:list pour vérifier que toutes tes routes sont enregistrées.
  5. Défi : Ouvre le simulateur ci-dessous. Parcours les 5 opérations CRUD et observe le code ↔ SQL ↔ réponse pour chaque étape.

⚡ Simulateur — CRUD complet d'une API REST

Étape 1/5
📝 Pseudo-code
1# CRUD complet — API REST pour les articles
2Route::get('/posts', [PostController::class, 'index']); # ⬅ LISTER (GET)
3Route::post('/posts', [PostController::class, 'store']); # ⬅ CRÉER (POST)
4Route::get('/posts/{id}', [PostController::class, 'show']); # ⬅ AFFICHER (GET)
5Route::put('/posts/{id}', [PostController::class, 'update']); # ⬅ MODIFIER (PUT)
6Route::delete('/posts/{id}', [PostController::class, 'destroy']); # ⬅ SUPPRIMER (DELETE)
🔄 CRUD REST — Posts
GET/posts
POST/posts
GET/posts/1
PUT/posts/1
DELETE/posts/1
GET/api/posts200
🐘 Contrôleur — index()
$posts = Post::all();
return response()->json($posts);
🗄️ SQL généré
SELECT * FROM posts
📦 Réponse JSON
[{"id":1,"title":"Article 1"},{"id":2,"title":"Article 2"}]
GET /api/posts retourne un tableau JSON de tous les articles. C'est l'opération la plus fréquente.
💡 Résumé CRUD REST
GET /posts
index() → all()
POST /posts
store() → create()
GET /posts/1
show() → findOrFail()
PUT /posts/1
update() → update()
DELETE /posts/1
destroy() → delete()

index() retourne une collection de tous les modèles. Laravel les convertit automatiquement en JSON.