Créer une API REST avec Laravel 12 : Guide complet et bonnes pratiques

anthowd anthowd
Créer son api rest Laravel 12 - API

Tu veux apprendre à créer une API REST avec Laravel 12 ? Tu es au bon endroit. Dans ce tutoriel, on va construire ensemble une API moderne, sécurisée et performante, en partant de zéro.

Si tu débutes avec Laravel ou que tu n’as jamais créé d’API REST, ce guide va te montrer pas à pas les bonnes pratiques actuelles. On va couvrir l’installation, la structure du projet, la validation, la sécurité et les performances. À la fin de cet article, tu sauras créer une API complète, prête à être consommée par un front JavaScript (React, Vue, Svelte) ou une application mobile.

Pourquoi créer une API REST avec Laravel 12 ?

Laravel est l’un des frameworks PHP les plus utilisés au monde pour créer des applications web et des APIs. La version 12 apporte des nouveautés qui simplifient encore plus le développement d’APIs :

  • Commande install:api dédiée
  • Support natif des UUIDv7
  • Nouvelles méthodes de validation renforcée
  • Outils de debug améliorés

Une API REST bien construite te permet de :

  • Séparer le backend du frontend (architecture découplée)
  • Créer des applications mobiles connectées
  • Exposer des données pour d’autres développeurs
  • Construire des SaaS et produits scalables

1. Installer Laravel 12 pour une API

La première étape consiste à créer un nouveau projet Laravel configuré spécialement pour les APIs.

Installation de base

composer create-project laravel/laravel mon-api
cd mon-api
php artisan install:api
Langage du code : Bash (bash)

Qu’est-ce que install:api fait pour toi ?

Cette commande prépare ton projet pour une API :

  • Crée un fichier routes/api.php dédié aux routes d’API
  • Configure les middlewares adaptés
  • Évite de mélanger routes web et routes API
  • Installe les dépendances nécessaires (comme Sanctum)

Tu obtiens une base propre, organisée et prête à recevoir tes endpoints.

Structure des dossiers après installation

mon-api/
├── app/
│   ├── Http/
│   │   ├── Controllers/
│   │   ├── Requests/
│   │   └── Resources/
│   ├── Models/
│   └── Services/
├── routes/
│   ├── api.php      ← Tes routes d'API ici
│   └── web.php
└── database/
    └── migrations/
Langage du code : Texte brut (plaintext)

2. Comprendre les routes API dans Laravel

Dans Laravel, les routes API sont séparées des routes web. Elles se trouvent dans routes/api.php et sont automatiquement préfixées par /api.

Exemple de route simple

// routes/api.php
use Illuminate\Support\Facades\Route;

Route::get('/hello', function () {
    return response()->json([
        'message' => 'Bienvenue sur mon API Laravel 12'
    ]);
});

Langage du code : PHP (php)

Cette route sera accessible à l’URL : http://localhost:8000/api/hello

Tester ta première route

Lance ton serveur de développement :

php artisan serve
Langage du code : Bash (bash)

Puis teste avec curl, Postman ou directement dans ton navigateur :

curl http://localhost:8000/api/helloLangage du code : Bash (bash)

Tu devrais recevoir :

<code>{
    "message": "Bienvenue sur mon API Laravel 12"
}</code>Langage du code : JSON / JSON avec commentaires (json)

3. Utiliser des UUIDs modernes (UUIDv7)

Par défaut, Laravel utilise des identifiants numériques auto-incrémentés (1, 2, 3…). Pour une API moderne, il est recommandé d’utiliser des UUIDs (Universally Unique Identifiers).

Pourquoi utiliser des UUIDs dans une API ?

Les UUIDs offrent plusieurs avantages :

  • Identifiants uniques même en environnement distribué
  • Plus difficiles à deviner (meilleure sécurité)
  • Pas de problème de concurrence lors de l’insertion
  • Compatible avec les architectures microservices

Laravel 12 supporte nativement les UUIDv7, qui combinent :

  • L’unicité des UUIDs classiques
  • Un tri chronologique naturel (comme les IDs auto-incrémentés)

Configurer un modèle avec UUIDv7

// app/Models/Article.php
namespace App\Models;

use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    use HasUuids;

    protected $keyType = 'string';
    public $incrementing = false;

    protected $fillable = ['title', 'content', 'author_id'];
}
Langage du code : PHP (php)

Migration correspondante

// database/migrations/xxxx_create_articles_table.php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->uuid('id')->primary();
            $table->string('title');
            $table->text('content');
            $table->uuid('author_id');
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('articles');
    }
};

Langage du code : PHP (php)

Lance la migration :

php artisan migrate
Langage du code : Bash (bash)

Maintenant, tes articles auront des identifiants du type : 01937ba2-8c3f-7b5d-a123-456789abcdef


4. Valider les données entrantes (Form Requests)

Dans une API, la validation est cruciale. Tu dois t’assurer que les données reçues sont correctes avant de les enregistrer en base.

Laravel propose les Form Requests, des classes dédiées à la validation qui gardent tes controllers propres.

Créer un Form Request

php artisan make:request StoreArticleRequest
Langage du code : Bash (bash)

Définir les règles de validation

// app/Http/Requests/StoreArticleRequest.php
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreArticleRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true; // À adapter selon ta logique d'autorisation
    }

    public function rules(): array
    {
        return [
            'title'   => 'required|string|max:255',
            'content' => 'required|string|min:50',
            'author_id' => 'required|uuid|exists:users,id'
        ];
    }

    public function messages(): array
    {
        return [
            'title.required'   => 'Le titre est obligatoire',
            'content.min'      => 'Le contenu doit faire au moins 50 caractères',
            'author_id.exists' => 'Cet auteur n\'existe pas'
        ];
    }
}

Langage du code : PHP (php)

Validation sécurisée avec secureValidate()

Laravel 12 introduit secureValidate(), qui ajoute une couche de sécurité supplémentaire en nettoyant automatiquement les entrées potentiellement dangereuses.

public function validateResolved()
{
    $this->secureValidate(); // Valide ET sécurise les données
}

Langage du code : PHP (php)

Cette méthode protège contre certaines injections et formate correctement les données avant leur utilisation.


5. Structurer proprement ton API (Controllers)

Un bon controller d’API doit être simple et lisible. Il orchestre les opérations, mais ne contient pas de logique métier complexe.

Créer un Controller

php artisan make:controller ArticleController --apiLangage du code : Bash (bash)

L’option --api crée automatiquement les méthodes CRUD adaptées aux APIs (sans create et edit qui sont pour les vues).

Exemple de Controller propre

// app/Http/Controllers/ArticleController.php
namespace App\Http\Controllers;

use App\Http\Requests\StoreArticleRequest;
use App\Http\Resources\ArticleResource;
use App\Models\Article;
use Illuminate\Http\Request;

class ArticleController extends Controller
{
    public function index()
    {
        $articles = Article::with('author')->latest()->paginate(15);
        return ArticleResource::collection($articles);
    }

    public function store(StoreArticleRequest $request)
    {
        $article = Article::create($request->validated());
        return new ArticleResource($article);
    }

    public function show(Article $article)
    {
        return new ArticleResource($article);
    }

    public function update(StoreArticleRequest $request, Article $article)
    {
        $article->update($request->validated());
        return new ArticleResource($article);
    }

    public function destroy(Article $article)
    {
        $article->delete();
        return response()->json(['message' => 'Article supprimé'], 200);
    }
}
Langage du code : PHP (php)

Enregistrer les routes

// routes/api.php
use App\Http\Controllers\ArticleController;

Route::apiResource('articles', ArticleController::class);

Langage du code : PHP (php)

Cette seule ligne crée automatiquement toutes les routes REST :

  • GET /api/articles → index()
  • POST /api/articles → store()
  • GET /api/articles/{id} → show()
  • PUT/PATCH /api/articles/{id} → update()
  • DELETE /api/articles/{id} → destroy()

6. Formater les réponses JSON (API Resources)

Les API Resources transforment tes modèles Eloquent en réponses JSON cohérentes et personnalisables.

Créer une Resource

php artisan make:resource ArticleResourceLangage du code : Bash (bash)

Définir le format de sortie

// app/Http/Resources/ArticleResource.php
namespace App\Http\Resources;

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

class ArticleResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id'         => $this->id,
            'title'      => $this->title,
            'content'    => $this->content,
            'author'     => [
                'id'   => $this->author->id,
                'name' => $this->author->name
            ],
            'created_at' => $this->created_at->format('d/m/Y H:i'),
            'updated_at' => $this->updated_at->diffForHumans()
        ];
    }
}
Langage du code : PHP (php)

Avantages des Resources

Les Resources permettent de :

  • Contrôler exactement les données exposées
  • Cacher certains champs sensibles (mots de passe, tokens)
  • Formater les dates et valeurs de façon cohérente
  • Créer différentes vues du même modèle
  • Gérer facilement les relations (author, comments, etc.)

7. Sécuriser ton API avec Laravel Sanctum

Une API publique sans authentification peut être utilisée par n’importe qui. Laravel Sanctum est la solution officielle pour sécuriser tes APIs facilement.

Installation de Sanctum

Sanctum est normalement installé avec install:api, mais vérifie :

composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate
Langage du code : Bash (bash)

Configuration de base

Dans config/sanctum.php, configure les domaines autorisés :

'stateful' => explode(',', env(
    'SANCTUM_STATEFUL_DOMAINS',
    'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000'
)),
Langage du code : PHP (php)

Créer un système d’authentification

Ajoute une route de login :

// routes/api.php
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;

Route::post('/login', function (Request $request) {
    $request->validate([
        'email'    => 'required|email',
        'password' => 'required'
    ]);

    $user = User::where('email', $request->email)->first();

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

    $token = $user->createToken('api-token')->plainTextToken;

    return response()->json([
        'user'  => $user,
        'token' => $token
    ]);
});

Langage du code : PHP (php)

Protéger tes routes

// routes/api.php
Route::middleware('auth:sanctum')->group(function () {
    Route::apiResource('articles', ArticleController::class);
    
    Route::get('/me', function (Request $request) {
        return $request->user();
    });
});

Langage du code : PHP (php)

Maintenant, pour accéder à ces routes, il faut envoyer un header Authorization: Bearer {token} avec chaque requête.


8. Limiter les requêtes (Rate Limiting)

Le Rate Limiting évite qu’un utilisateur ou un bot abuse de ton API en faisant trop de requêtes.

Configuration du Rate Limiter

// app/Providers/RouteServiceProvider.php
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;

protected function configureRateLimiting()
{
    RateLimiter::for('api', function (Request $request) {
        return Limit::perMinute(60)->by(
            $request->user()?->id ?: $request->ip()
        );
    });
}

Langage du code : PHP (php)

Cette configuration limite à 60 requêtes par minute par utilisateur ou par IP.

Application sur tes routes

// routes/api.php
Route::middleware(['auth:sanctum', 'throttle:api'])->group(function () {
    Route::apiResource('articles', ArticleController::class);
});
Langage du code : PHP (php)

Si un client dépasse la limite, il recevra une erreur 429 Too Many Requests.


9. Optimiser les performances de ton API

Une API lente = mauvaise expérience utilisateur. Voici comment optimiser tes requêtes dès le départ.

Éviter le problème N+1 avec Eager Loading

Le problème N+1 survient quand tu charges une relation dans une boucle, créant des dizaines de requêtes SQL inutiles.

Mauvais exemple :

$articles = Article::all();
foreach ($articles as $article) {
    echo $article->author->name; // 1 requête par article !
}

Langage du code : PHP (php)

Bonne pratique :

$articles = Article::with('author')->get();
foreach ($articles as $article) {
    echo $article->author->name; // 1 seule requête SQL !
}

Langage du code : PHP (php)

Utiliser cursorPaginate() pour les grandes listes

Pour les listes avec beaucoup d’éléments, cursorPaginate() est plus performant que paginate() :

public function index()
{
    $articles = Article::with('author')
                       ->latest()
                       ->cursorPaginate(15);
    
    return ArticleResource::collection($articles);
}
Langage du code : PHP (php)

La pagination par curseur est idéale pour :

  • Les flux infinis (type Twitter, Instagram)
  • Les très grosses tables (milliers d’entrées)
  • Les performances de chargement optimales

10. Déboguer facilement avec ddBody()

Laravel 12 introduit ddBody(), un outil de debug spécifique aux APIs qui affiche le contenu brut d’une requête.

Utilisation en développement

// routes/api.php
Route::post('/test', function () {
    ddBody(); // Affiche body + headers de la requête
});
Langage du code : PHP (php)

Envoie une requête POST avec Postman et tu verras :

  • Le body JSON complet
  • Tous les headers HTTP
  • Les données envoyées

C’est très utile pour comprendre pourquoi une requête ne fonctionne pas comme prévu.

Important : retire ces appels en production !


11. Exemple complet : CRUD d’une API d’articles

Récapitulons tout ce qu’on a vu dans un exemple fonctionnel complet.

Modèle Article

// app/Models/Article.php
namespace App\Models;

use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Article extends Model
{
    use HasUuids;

    protected $keyType = 'string';
    public $incrementing = false;

    protected $fillable = ['title', 'content', 'author_id'];

    public function author(): BelongsTo
    {
        return $this->belongsTo(User::class, 'author_id');
    }
}

Langage du code : PHP (php)

Resource Article

// app/Http/Resources/ArticleResource.php
namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class ArticleResource extends JsonResource
{
    public function toArray($request): array
    {
        return [
            'id'      => $this->id,
            'title'   => $this->title,
            'content' => $this->when(
                $request->routeIs('articles.show'),
                $this->content
            ),
            'author'  => [
                'id'   => $this->author->id,
                'name' => $this->author->name
            ],
            'created_at' => $this->created_at->format('d/m/Y'),
        ];
    }
}

Langage du code : PHP (php)

Controller Article

// app/Http/Controllers/ArticleController.php
namespace App\Http\Controllers;

use App\Http\Requests\StoreArticleRequest;
use App\Http\Resources\ArticleResource;
use App\Models\Article;

class ArticleController extends Controller
{
    public function index()
    {
        return ArticleResource::collection(
            Article::with('author')->latest()->cursorPaginate(15)
        );
    }

    public function store(StoreArticleRequest $request)
    {
        $article = Article::create([
            ...$request->validated(),
            'author_id' => $request->user()->id
        ]);

        return new ArticleResource($article);
    }

    public function show(Article $article)
    {
        $article->load('author');
        return new ArticleResource($article);
    }

    public function update(StoreArticleRequest $request, Article $article)
    {
        $this->authorize('update', $article);
        $article->update($request->validated());
        
        return new ArticleResource($article);
    }

    public function destroy(Article $article)
    {
        $this->authorize('delete', $article);
        $article->delete();
        
        return response()->json(['message' => 'Article supprimé']);
    }
}

Langage du code : PHP (php)

Routes complètes

// routes/api.php
use App\Http\Controllers\ArticleController;

Route::post('/login', [AuthController::class, 'login']);

Route::middleware(['auth:sanctum', 'throttle:api'])->group(function () {
    Route::apiResource('articles', ArticleController::class);
    Route::get('/me', fn($req) => $req->user());
});
Langage du code : PHP (php)

Conclusion : tu es prêt à créer des APIs avec Laravel 12

Tu as maintenant toutes les bases pour créer une API REST moderne avec Laravel 12 :

  • Installation et configuration avec install:api
  • Identifiants UUIDv7 pour plus de scalabilité
  • Validation stricte avec Form Requests et secureValidate()
  • Structure propre avec Controllers minimalistes et Resources
  • Sécurité via Sanctum et Rate Limiting
  • Performances optimisées avec Eager Loading et pagination par curseur

N’hésite pas à pratiquer en créant une petite API (gestion de tâches, blog, catalogue de produits) pour bien assimiler ces concepts.

Tu trouveras d’autres tutoriels Laravel et conseils de développement web régulièrement sur ce blog.

Bon code ! 🚀

Articles similaires