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ération | HTTP | SQL | Méthode du contrôleur |
|---|---|---|---|
| Create | POST | INSERT | store() |
| Read (tous) | GET | SELECT | index() |
| Read (un) | GET | SELECT WHERE | show() |
| Update | PUT/PATCH | UPDATE | update() |
| Delete | DELETE | DELETE | destroy() |
💡 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
| Code | Signification | Usage |
|---|---|---|
| 200 | OK | GET, PUT réussis |
| 201 | Created | POST réussi (nouvelle ressource) |
| 204 | No Content | DELETE réussi |
| 400 | Bad Request | Données invalides (hors validation) |
| 404 | Not Found | Ressource inexistante |
| 422 | Unprocessable Entity | Échec de validation |
| 500 | Internal Server Error | Erreur serveur |
Bonnes pratiques ✅
- Toujours valider les entrées avec
$request->validate()avantcreate()ouupdate() - Utiliser les bons codes HTTP : 201 pour création, 204 pour suppression, 404 si non trouvé
- Utiliser Resource::collection() pour formater la réponse (API Resources)
- Pagine les listes :
Post::paginate(15)plutôt queall()pour les gros volumes - Toujours gérer les erreurs :
findOrFail()+ try/catch si nécessaire - Documenter l'API avec des annotations PHPDoc ou un outil comme Scribe
Pièges fréquents 🚨
| Piège | Solution |
|---|---|
❌ Utiliser GET /api/posts/delete/1 | Utilise 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 code | Laravel le fait automatiquement avec findOrFail() |
| ❌ Créer sans validation | Les données invalides corrompent la BDD |
Exercices pour toi 🎯
- Pratique : Crée un contrôleur
ProductControllercomplet avec les 5 méthodes CRUD. - Routes : Enregistre les 5 routes REST pour
/api/products. - Validation : Ajoute une validation avec
titlerequis,pricenumérique requis,stockentier optionnel. - Test : Utilise
php artisan route:listpour vérifier que toutes tes routes sont enregistrées. - 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$posts = Post::all(); return response()->json($posts);
SELECT * FROM posts[{"id":1,"title":"Article 1"},{"id":2,"title":"Article 2"}]index() → all()
store() → create()
show() → findOrFail()
update() → update()
destroy() → delete()
index() retourne une collection de tous les modèles. Laravel les convertit automatiquement en JSON.