L3 Info : PHP et Applications Web
 
◃  Ch. 13 Symfony 7.4  ▹
 

Symfony et les API

  • Objectif : Créer des interfaces de programmation (API) pour permettre à des clients (web, mobile, IoT) d’interagir avec votre application Symfony de manière sécurisée et standardisée.

  • Symfony :

    • Intègre API Platform (pour les API RESTful et GraphQL)
    • Intègre Symfony Serializer pour la sérialisation/désérialisation.
    • Supporte les standards JSON:API, OpenAPI/Swagger, JWT pour l’authentification.
    • Facilite la création d’API modulaires, scalables et documentées.
  • Quelques définitions (et rappels) :

    • REST ( Representational State Transfer ) : style d’architecture pour les API (verbes HTTP, ressources, stateless).
    • Endpoint : URL exposant une ressource (ex: /api/users).
    • Serializer : Convertit les objets PHP en JSON/XML et vice versa.
    • Désérialisation :Transformation de données JSON/XML en objets PHP.
    • JWT : Token d’authentification pour les API (JSON Web Token).
    • OpenAPI : Standard pour documenter les API (anciennement Swagger).
  • Création d’une API RESTful avec Symfony

    • Installation des dépendances
      composer require api  # Installe API Platform, Symfony Serializer, etc.
      composer require lexik/jwt-authentication-bundle  # Pour l'authentification JWT
    • Configuration de base
      • Fichier config/packages/api_platform.yaml
        api_platform:
        title: 'Mon API Symfony'
        description: 'Une API pour mon application.'
        version: '1.0.0'
        formats:
            jsonld:
                mime_types: ['application/ld+json']
            json:
                mime_types: ['application/json']
      • Fichier config/routes.yaml
        api:
           resource: .
           type: api_platform
           prefix: /api
    • Exemple de création d’une ressource API : Entité Book

      // src/Entity/Book.php
      namespace App\Entity;
      
      use ApiPlatform\Metadata\ApiResource;
      use Doctrine\ORM\Mapping as ORM;
      
      #[ApiResource]  // Annotation pour exposer l'entité comme ressource API
      #[ORM\Entity]
      class Book
      {
          #[ORM\Id, ORM\GeneratedValue, ORM\Column]
          private ?int $id = null;
      
          #[ORM\Column]
          public string $title;
      
          #[ORM\Column]
          public string $author;
      
          #[ORM\Column]
          public int $year;
      
          // Getters et setters...
      }
    • Génère automatiquement les endpoints :
      • GET /api/books (liste des livres)
      • POST /api/books (création)
      • GET /api/books/{id} (détails)
      • PUT /api/books/{id} (mise à jour)
      • DELETE /api/books/{id} (suppression)
    • Personnalisation des endpoints
    • Ajouter des filtres

       use ApiPlatform\Metadata\ApiFilter;
       use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
      
       #[ApiResource]
       #[ApiFilter(SearchFilter::class, properties: ['title' => 'partial'])]
       class Book { ... }
    • Utilisation :
       GET /api/books?title=Symfony
         → Filtre les livres dont le titre contient "Symfony".
    • Désactiver des méthodes
       #[ApiResource(
           operations: [
              new GetCollection(),
              new Post(),
              new Get(),
              // new Put(),  // Désactivé
              // new Delete(),  // Désactivé
             ]
           )]
       class Book { ... }
  • Sérialisation et désérialisation

    • Utilisation du Serializer : Symfony utilise le composant Serializer pour convertir les objets en JSON/XML.
    • Exemple : Personnaliser la sérialisation pour exclure le champ author (il n'est pas inclus dans les requêtes POST)

      // src/Entity/Book.php
      use Symfony\Component\Serializer\Annotation\Groups;
      
      #[ApiResource(
        normalizationContext: ['groups' => ['book:read']],
        denormalizationContext: ['groups' => ['book:write']]
        )]
      class Book
      {
        #[Groups(['book:read'])]
        private ?int $id = null;
      
        #[Groups(['book:read', 'book:write'])]
        public string $title;
      
        #[Groups(['book:read'])]
        public string $author;
      }
    • Gestion des relations
      // src/Entity/Book.php
      #[ORM\ManyToOne(targetEntity: Author::class)]
      #[Groups(['book:read', 'book:write'])]
      public Author $author;
  • Authentification et sécurité

    • Utilisation de JWT :
      • Configuration
        # config/packages/security.yaml
        security:
            providers:
                jwt:
                    lexik_jwt: ~
            firewalls:
                api:
                    pattern: ^/api
                    stateless: true
                    jwt: ~`
      • Génération des clés JWT
         mkdir -p config/jwt 
         openssl genpkey -out config/jwt/private.pem -aes256 -algorithm rsa -pkeyopt rsa_keygen_bits:4096 
         openssl pkey -in config/jwt/private.pem -out config/jwt/public.pem -pubout
      • Récupération du token
         curl -X POST -H "Content-Type: application/json" http://localhost:8000/api/login_check -d '{"username":"toto@webmail.ia","totopassword":"totopassword"}'
      • Réponse :
        { "token": "token_jwt_reçu" }
      • Utilisation du token :
         curl -H "Authorization: Bearer token_jwt_reçu" http://localhost:8000/api/books
    • Protection des endpoints
        #[ApiResource(
            security: "is_granted('ROLE_USER')"
            )]
        class Book { ... }
  • Documentation de l’API

    • Génération automatique avec API Platform
      • Accéder à /api dans votre navigateur pour voir la documentation interactive (Swagger UI).
      • Pour exporter la spécification OpenAPI :
         php bin/console api:openapi:export --output=openapi.json
      • Exemple de documentation OpenAPI :
         # config/api_platform/openapi.yaml
         openapi: 3.0.0
         info:
           title: Mon API Symfony
           version: 1.0.0
         paths:
           /api/books:
             get:
               summary: Liste des livres
               responses:
                 200:
                 description: OK
  • Exemple Complet ;

    • Entité book

      // src/Entity/Book.php
      namespace App\Entity;
      
      use ApiPlatform\Metadata\ApiResource;
      use Doctrine\ORM\Mapping as ORM;
      use Symfony\Component\Validator\Constraints as Assert;
      use Symfony\Component\Serializer\Annotation\Groups;
      
      #[ApiResource(
         normalizationContext: ['groups' => ['book:read']],
         denormalizationContext: ['groups' => ['book:write']],
         security: "is_granted('ROLE_USER')"
      )]
      #[ORM\Entity]
      class Book
      {
         #[ORM\Id, ORM\GeneratedValue, ORM\Column]
         #[Groups(['book:read'])]
         private ?int $id = null;
      
         #[ORM\Column]
         #[Groups(['book:read', 'book:write'])]
         #[Assert\NotBlank]
         public string $title;
      
         #[ORM\Column]
         #[Groups(['book:read', 'book:write'])]
         #[Assert\NotBlank]
         public string $author;
      
         #[ORM\Column]
         #[Groups(['book:read', 'book:write'])]
         #[Assert\Positive]
         public int $year;
      
         // Getters et setters...
      }
    • Exemples de requêtes
    Méthode Endpoint Description Exemple de requête
    GET /api/books Liste des livres curl -H "Authorization: Bearer TOKEN" http://localhost:8000/api/books
    POST /api/books Créer un livre curl -X POST -H "Authorization: Bearer TOKEN" -d '{"title":"Le cerveau solitaire","author":"Jeff Sutton","year":1974}' http://localhost:8000/api/books
    GET /api/books/{id} Détails d’un livre curl -H "Authorization: Bearer TOKEN" http://localhost:8000/api/books/1
    PUT /api/books/{id} Mettre à jour un livre curl -X PUT -H "Authorization: Bearer TOKEN" -d '{"title":"Le nouveau cerveau solitaire"}' http://localhost:8000/api/books/1
    DELETE /api/books/{id} Supprimer un livre curl -X DELETE -H "Authorization: Bearer TOKEN" http://localhost:8000/api/books/1
  • Ressources :