Skip to Content

Chapitre 11.1 — API Platform : concepts & première resource

Partie 11 : API Platform — Chapitre 1/8 Version de référence : API Platform 4 / Symfony 7.4.

⏱️ TL;DR

  • API Platform est un framework d’API bâti sur Symfony. Un attribut #[ApiResource] sur une classe génère une API REST complète : liste, détail, création, modification, suppression, avec pagination, validation, et documentation OpenAPI automatique.
  • Chaque opération (GET collection, GET item, POST, PATCH, DELETE) est configurable, exposable ou non.
  • Format par défaut : JSON-LD (JSON + @context/@id/@type, vocabulaire Hydra) — auto-descriptif ; JSON classique aussi disponible (négociation de contenu).
  • Architecture : un state provider lit les données (Doctrine par défaut), un state processor les écrit. On peut les remplacer (DTO, source externe).
  • Une Swagger UI interactive est servie sur /api — testable dans le navigateur.
  • Pour un dev Next.js : c’est un générateur d’API façon Hasura/PostgREST, mais sur vos entités Doctrine et entièrement personnalisable en PHP.

🎯 Objectifs

  • Installer API Platform et exposer une première resource.
  • Comprendre les opérations générées et les formats.
  • Lire la documentation Swagger auto-générée.
  • Saisir l’architecture provider/processor.

1. Ce qu’API Platform fait pour vous

Écrire une API REST à la main (contrôleurs, sérialisation, pagination, filtres, doc, validation, gestion d’erreurs) pour chaque entité est long et répétitif. API Platform génère tout ça à partir d’un attribut, tout en restant personnalisable à chaque étape.

composer require api

L’alias Flex api installe API Platform et configure tout (route /api, Swagger UI, formats).

2. Une première resource

Il suffit d’annoter une entité (ou un DTO) avec #[ApiResource] :

// src/Entity/Provider.php use ApiPlatform\Metadata\ApiResource; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] #[ApiResource] // ← génère une API REST complète pour Provider class Provider { #[ORM\Id, ORM\GeneratedValue, ORM\Column] private ?int $id = null; #[ORM\Column(length: 255)] private string $name; #[ORM\Column(length: 255, unique: true)] private string $slug; // getters/setters... }

C’est tout. Vous obtenez immédiatement ces endpoints :

OpérationMéthode + URLRôle
GetCollectionGET /api/providersliste (paginée)
GetGET /api/providers/{id}un prestataire
PostPOST /api/providerscréer
PatchPATCH /api/providers/{id}modifier partiellement
DeleteDELETE /api/providers/{id}supprimer

Avec, gratuitement : la pagination, la validation (vos #[Assert\...], Partie 9), la négociation de format, et la documentation.

3. Le format JSON-LD (et les autres)

Par défaut, API Platform répond en JSON-LD — du JSON enrichi de métadonnées Hydra :

{ "@context": "/api/contexts/Provider", "@id": "/api/providers/1", "@type": "Provider", "id": 1, "name": "Studio Zen", "slug": "studio-zen" }

Les champs @id, @type, @context rendent l’API auto-descriptive (hypermedia) : un client peut découvrir la structure et les liens. Une collection inclut aussi les infos de pagination (hydra:totalItems, hydra:view).

On peut demander du JSON classique (sans les @) via l’en-tête Accept: application/json — c’est souvent ce qu’on préfère côté Next.js pour sa simplicité. API Platform gère la négociation de contenu : le client choisit le format via Accept.

💡 Pour un dev Next.js : le JSON-LD peut surprendre. Retenez que vous pouvez travailler en JSON pur (Accept: application/json) si l’hypermedia ne vous sert pas. Le JSON-LD devient utile pour des clients génériques/l’interopérabilité ; pour un front Next.js sur mesure, du JSON typé suffit. On configurera le format préféré (chapitre 11.8).

4. La documentation interactive (Swagger UI)

Ouvrez https://localhost:8000/api : API Platform sert une Swagger UI (OpenAPI) qui liste toutes vos opérations, avec les schémas, et permet de les tester directement dans le navigateur (envoyer une requête, voir la réponse). C’est une documentation vivante, toujours à jour, générée depuis votre code.

💡 Pour un dev Next.js : cette doc OpenAPI est exploitable pour générer des types TypeScript et un client typé côté Next.js (via openapi-typescript, orval…). On obtient ainsi un client type-safe de bout en bout, sans écrire les types à la main — un atout majeur du couple API Platform + Next.js (chapitre 11.8).

5. Configurer les opérations

On expose ou restreint les opérations selon les besoins. Par exemple, une resource en lecture seule (pas de création/suppression via l’API) :

use ApiPlatform\Metadata\{ApiResource, Get, GetCollection}; #[ApiResource(operations: [ new GetCollection(), // GET /api/providers new Get(), // GET /api/providers/{id} // pas de Post/Patch/Delete → lecture seule ])] class Provider { /* ... */ }

On peut aussi configurer par opération : sécurité, groupes de sérialisation, pagination, filtres — chaque chapitre suivant approfondit un aspect.

6. L’architecture : providers & processors

Sous le capot (API Platform 3+), deux notions clés :

  • Un state provider récupère les données d’une opération de lecture. Par défaut, c’est le provider Doctrine (il interroge la base via votre entité).
  • Un state processor traite une opération d’écriture (persist/delete). Par défaut, le processor Doctrine (il persist/flush/remove).

Ce découplage est puissant : on peut remplacer le provider/processor pour lire depuis une source externe, écrire dans un service métier, ou travailler avec des DTO au lieu d’entités (chapitre 11.2). L’entité n’est pas obligatoirement la resource : on peut exposer un DTO et brancher un provider/processor custom.

Depuis Symfony 5 : si vous aviez touché à API Platform 2.x, l’architecture DataProvider/DataPersister a été remplacée par State Providers/Processors (API Platform 3), et la config des opérations est passée aux attributs dédiés (#[Get], #[Post]…) au lieu de collectionOperations/itemOperations. C’est plus clair et cohérent avec le reste de Symfony 7.

✏️ Exercices

Exercice 1. Exposez l’entité Service en API lecture seule (liste + détail uniquement). Écrivez l’attribut.

✅ Solution

use ApiPlatform\Metadata\{ApiResource, Get, GetCollection}; #[ApiResource(operations: [ new GetCollection(), new Get(), ])] class Service { /* ... */ }

Seuls GET /api/services et GET /api/services/{id} sont exposés ; pas de création/modification/suppression via l’API.

Exercice 2. Comment obtenir du JSON classique plutôt que du JSON-LD sur une requête, et pourquoi est-ce parfois préférable côté Next.js ?

✅ Solution

En envoyant l’en-tête Accept: application/json (négociation de contenu). C’est parfois préférable côté Next.js car le JSON-LD ajoute des champs @context/@id/@type (hypermedia Hydra) souvent inutiles pour un front sur mesure ; du JSON pur est plus simple à typer et à consommer. (On peut aussi configurer le format par défaut, chapitre 11.8.)

Exercice 3. Qu’est-ce qu’un state provider et un state processor, et que sont-ils par défaut ?

✅ Solution

Un state provider récupère les données d’une opération de lecture ; un state processor exécute une opération d’écriture (persist/delete). Par défaut, ce sont les provider/processor Doctrine (lecture depuis la base via l’entité, écriture via persist/flush/remove). On peut les remplacer pour utiliser des DTO, une source externe ou un service métier.

🧠 Quiz de révision

1. Que génère #[ApiResource] sur une entité ?

Une API REST complète (liste, détail, création, modification, suppression) avec pagination, validation et documentation OpenAPI — automatiquement.

2. Quel est le format de réponse par défaut, et qu’apporte-t-il ?

JSON-LD (avec @context/@id/@type, vocabulaire Hydra) : une API auto-descriptive (hypermedia). Du JSON classique est disponible via Accept: application/json.

3. Où se trouve la documentation interactive ?

Sur /api : une Swagger UI (OpenAPI) qui liste et permet de tester les opérations, générée depuis le code.

4. Comment expose-t-on une resource en lecture seule ?

En ne déclarant que les opérations de lecture : operations: [new GetCollection(), new Get()] (sans Post/Patch/Delete).

5. À quoi servent state providers et processors ?

Le provider récupère les données (lecture), le processor exécute les écritures — Doctrine par défaut, remplaçables pour DTO/source externe/service métier.


Prochain chapitre : 11.2 — Sérialisation — groupes, DTO, et l’art d’exposer le juste nécessaire.