Terrain 11 — API Platform
🔍 Renfort : Partie 11.
1. Première resource ⭐
🕹️ Mission : exposer Provider en API REST complète.
✅ Solution
#[ORM\Entity]
#[ApiResource]
class Provider {}2. Lecture seule ⭐⭐
🕹️ Mission : exposer Service en liste + détail uniquement.
✅ Solution
#[ApiResource(operations: [new GetCollection(), new Get()])]
class Service {}3. Groupes read/write ⭐⭐⭐
🕹️ Mission : customerEmail en lecture ET écriture ; status/createdAt en lecture seule.
✅ Solution
#[ApiResource(
normalizationContext: ['groups' => ['booking:read']],
denormalizationContext: ['groups' => ['booking:write']],
)]
// #[Groups(['booking:read', 'booking:write'])] private string $customerEmail;
// #[Groups(['booking:read'])] private BookingStatus $status;4. Over-exposure ⭐⭐⭐
🕹️ Mission : pourquoi #[ApiResource] sur User sans groupes est dangereux ?
✅ Solution
Il expose (et laisse modifier) tous les champs, dont le hash du mot de passe et les rôles → fuite + élévation de privilèges. Toujours des groupes read/write explicites.
5. Filtre de recherche ⭐⭐⭐
🕹️ Mission : recherche partielle sur customerEmail, tri sur start.
✅ Solution
#[ApiFilter(SearchFilter::class, properties: ['customerEmail' => 'partial'])]
#[ApiFilter(OrderFilter::class, properties: ['start'])]
class Booking {}6. Erreur 422 ⭐⭐
🕹️ Mission : que renvoie l’API si le corps d’une création est invalide ?
✅ Solution
Un 422 (RFC 7807) avec la liste des violations — automatiquement, en réutilisant les #[Assert\...].
7. Sécurité par opération ⭐⭐⭐
🕹️ Mission : le détail via voter VIEW, la création via ROLE_USER.
✅ Solution
new Get(security: "is_granted('VIEW', object)"),
new Post(security: "is_granted('ROLE_USER')"),8. Publier en Mercure ⭐⭐⭐
🕹️ Mission : diffuser en temps réel les changements d’une resource.
✅ Solution
#[ApiResource(mercure: true)]
class Slot {}9. Types côté Next.js ⭐⭐⭐
🕹️ Mission : générer des types TS depuis l’API. Comment ?
✅ Solution
npx openapi-typescript http://localhost:8000/api/docs.json -o src/lib/api-types.ts (depuis la spec OpenAPI).
10. CORS ⭐⭐⭐
🕹️ Mission : le front localhost:3000 reçoit une erreur CORS. Trois vérifs ?
✅ Solution
allow_origin inclut l’origine exacte ; allow_headers contient Authorization ; allow_methods contient la méthode + OPTIONS. (Pas de * avec credentials.)
Terrain suivant : Async & temps réel.