Démarrer un Projet

Créer une API REST Complète avec Laravel

Guide pratique pour construire une API REST professionnelle avec Laravel : routes, controllers, validation, authentification JWT et bonnes pratiques de développement.

Introduction aux API REST

Les API REST (Representational State Transfer) sont devenues la norme pour la communication entre applications. Avec Laravel, créer une API robuste et maintenable est remarquablement simple, grâce à son écosystème riche et sa syntaxe élégante.

Dans ce guide, nous allons créer une API complète pour gérer une base d'utilisateurs, avec toutes les fonctionnalités essentielles : CRUD, authentification, validation, pagination et bien plus encore.

Pour qui est ce guide ?

Ce guide s'adresse aux développeurs ayant déjà une expérience avec Laravel et PHP, et souhaitant approfondir leurs connaissances en développement d'API RESTful.

Configuration de l'environnement

Avant de commencer, assurez-vous d'avoir Laravel installé. Créons un nouveau projet :

Terminal
composer create-project laravel/laravel api-rest-example
cd api-rest-example

Installez les packages nécessaires pour notre API :

Terminal
composer require laravel/sanctum
composer require tymon/jwt-auth

Important

Assurez-vous que votre version de PHP est 8.1 ou supérieure. Laravel 10 nécessite PHP 8.1+.

Routes et Controllers

Dans Laravel, les routes sont définies dans le fichier routes/api.php. Utilisons les routes API Resource pour gérer nos utilisateurs :

PHP - routes/api.php
use App\Http\Controllers\Api\UserController;
use Illuminate\Support\Facades\Route;

Route::prefix('v1')->group(function () {
    // Routes publiques
    Route::post('/register', [UserController::class, 'register']);
    Route::post('/login', [UserController::class, 'login']);
    
    // Routes protégées
    Route::middleware('auth:api')->group(function () {
        Route::apiResource('users', UserController::class);
        Route::get('/profile', [UserController::class, 'profile']);
        Route::put('/profile', [UserController::class, 'updateProfile']);
    });
});

Créons maintenant notre contrôleur UserController avec les méthodes CRUD :

PHP - app/Http/Controllers/Api/UserController.php
<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Requests\StoreUserRequest;
use App\Http\Requests\UpdateUserRequest;
use App\Http\Resources\UserResource;
use App\Models\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;

class UserController extends Controller
{
    /**
     * Afficher la liste des utilisateurs
     */
    public function index(Request $request): JsonResponse
    {
        $users = User::query()
            ->when($request->has('search'), function ($query) use ($request) {
                $query->where('name', 'like', '%' . $request->search . '%')
                    ->orWhere('email', 'like', '%' . $request->search . '%');
            })
            ->orderBy('created_at', 'desc')
            ->paginate($request->get('per_page', 15));
        
        return response()->json([
            'success' => true,
            'data' => UserResource::collection($users),
            'meta' => [
                'total' => $users->total(),
                'per_page' => $users->perPage(),
                'current_page' => $users->currentPage(),
                'last_page' => $users->lastPage(),
            ]
        ]);
    }
    
    /**
     * Créer un nouvel utilisateur
     */
    public function store(StoreUserRequest $request): JsonResponse
    {
        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
        ]);
        
        return response()->json([
            'success' => true,
            'message' => 'Utilisateur créé avec succès',
            'data' => new UserResource($user)
        ], 201);
    }
    
    /**
     * Afficher un utilisateur spécifique
     */
    public function show(User $user): JsonResponse
    {
        return response()->json([
            'success' => true,
            'data' => new UserResource($user)
        ]);
    }
    
    /**
     * Mettre à jour un utilisateur
     */
    public function update(UpdateUserRequest $request, User $user): JsonResponse
    {
        $user->update($request->validated());
        
        return response()->json([
            'success' => true,
            'message' => 'Utilisateur mis à jour avec succès',
            'data' => new UserResource($user)
        ]);
    }
    
    /**
     * Supprimer un utilisateur
     */
    public function destroy(User $user): JsonResponse
    {
        $user->delete();
        
        return response()->json([
            'success' => true,
            'message' => 'Utilisateur supprimé avec succès'
        ]);
    }
    
    /**
     * Inscription d'un nouvel utilisateur
     */
    public function register(StoreUserRequest $request): JsonResponse
    {
        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
        ]);
        
        $token = $user->createToken('auth_token')->plainTextToken;
        
        return response()->json([
            'success' => true,
            'message' => 'Inscription réussie',
            'data' => new UserResource($user),
            'token' => $token
        ], 201);
    }
    
    /**
     * Connexion utilisateur
     */
    public function login(Request $request): JsonResponse
    {
        $request->validate([
            'email' => 'required|email',
            'password' => 'required'
        ]);
        
        if (!auth()->attempt($request->only('email', 'password'))) {
            return response()->json([
                'success' => false,
                'message' => 'Identifiants incorrects'
            ], 401);
        }
        
        $user = auth()->user();
        $token = $user->createToken('auth_token')->plainTextToken;
        
        return response()->json([
            'success' => true,
            'message' => 'Connexion réussie',
            'data' => new UserResource($user),
            'token' => $token
        ]);
    }
    
    /**
     * Profil de l'utilisateur connecté
     */
    public function profile(): JsonResponse
    {
        return response()->json([
            'success' => true,
            'data' => new UserResource(auth()->user())
        ]);
    }
}

Validation des données

La validation est cruciale pour la sécurité de votre API. Utilisons les Form Requests de Laravel :

PHP - app/Http/Requests/StoreUserRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Password;

class StoreUserRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }
    
    public function rules(): array
    {
        return [
            'name' => 'required|string|max:255',
            'email' => 'required|email|unique:users,email',
            'password' => [
                'required',
                'confirmed',
                Password::min(8)
                    ->letters()
                    ->mixedCase()
                    ->numbers()
                    ->symbols()
            ]
        ];
    }
    
    public function messages(): array
    {
        return [
            'name.required' => 'Le nom est obligatoire',
            'email.required' => 'L\'email est obligatoire',
            'email.email' => 'L\'email doit être valide',
            'email.unique' => 'Cet email est déjà utilisé',
            'password.required' => 'Le mot de passe est obligatoire',
            'password.confirmed' => 'Les mots de passe ne correspondent pas',
        ];
    }
}

API Resources

Les API Resources permettent de transformer vos modèles en réponses JSON cohérentes :

PHP - app/Http/Resources/UserResource.php
<?php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
            'email_verified_at' => $this->email_verified_at,
            'created_at' => $this->created_at->format('Y-m-d H:i:s'),
            'updated_at' => $this->updated_at->format('Y-m-d H:i:s'),
            'links' => [
                'self' => route('api.users.show', $this->id),
                'update' => route('api.users.update', $this->id),
                'delete' => route('api.users.destroy', $this->id),
            ]
        ];
    }
}

Tests unitaires

Testez votre API avec PHPUnit pour garantir sa fiabilité :

PHP - tests/Feature/Api/UserApiTest.php
<?php

namespace Tests\Feature\Api;

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Hash;
use Tests\TestCase;

class UserApiTest extends TestCase
{
    use RefreshDatabase;
    
    /** @test */
    public function it_can_register_a_new_user()
    {
        $response = $this->postJson('/api/v1/register', [
            'name' => 'John Doe',
            'email' => 'john@example.com',
            'password' => 'Password123!',
            'password_confirmation' => 'Password123!'
        ]);
        
        $response->assertStatus(201)
            ->assertJsonStructure([
                'success',
                'message',
                'data' => [
                    'id',
                    'name',
                    'email'
                ],
                'token'
            ]);
        
        $this->assertDatabaseHas('users', [
            'email' => 'john@example.com'
        ]);
    }
    
    /** @test */
    public function it_can_login_with_valid_credentials()
    {
        $user = User::factory()->create([
            'email' => 'john@example.com',
            'password' => Hash::make('Password123!')
        ]);
        
        $response = $this->postJson('/api/v1/login', [
            'email' => 'john@example.com',
            'password' => 'Password123!'
        ]);
        
        $response->assertStatus(200)
            ->assertJsonStructure([
                'success',
                'message',
                'data',
                'token'
            ]);
    }
    
    /** @test */
    public function it_can_list_users()
    {
        User::factory()->count(3)->create();
        $user = User::factory()->create();
        
        $response = $this->actingAs($user, 'sanctum')
            ->getJson('/api/v1/users');
        
        $response->assertStatus(200)
            ->assertJsonStructure([
                'success',
                'data',
                'meta'
            ]);
    }
}

Bonnes pratiques

Pour maintenir une API de qualité, suivez ces bonnes pratiques :

1. Versionnez votre API

Toujours versionner votre API (v1, v2, etc.) pour assurer la compatibilité avec les clients existants.

2. Utilisez les codes HTTP appropriés

  • 200 : Succès
  • 201 : Créé
  • 400 : Requête invalide
  • 401 : Non authentifié
  • 403 : Non autorisé
  • 404 : Non trouvé
  • 422 : Validation échouée
  • 500 : Erreur serveur

3. Paginez les résultats

Toujours paginer les résultats de liste pour éviter de surcharger le serveur et le client.

4. Rate Limiting

Implémentez le rate limiting pour protéger votre API contre les abus :

PHP - app/Http/Kernel.php
protected $middlewareGroups = [
    'api' => [
        'throttle:api',
        // autres middlewares...
    ],
];

Prochaines étapes

Maintenant que vous avez une API de base, vous pouvez ajouter des fonctionnalités avancées comme la documentation automatique avec Swagger, la mise en cache Redis, ou l'intégration avec des services tiers.

Vous avez maintenant toutes les bases pour créer une API REST professionnelle avec Laravel. N'hésitez pas à explorer la documentation officielle de Laravel pour approfondir vos connaissances.

RG

Roger Gnanih

Développeur FullStack avec 5 ans d'expérience en Laravel, Angular et Flutter. Passionné par la création de solutions digitales innovantes pour l'Afrique. J'aime partager mes connaissances à travers des articles techniques et tutoriels.