Pourquoi API REST avec Symfony ?
Les API REST (Representational State Transfer) sont un modèle d'architecture logicielle qui permet de créer des services web interopérables et évolutifs. En tant que développeur Symfony, vous aurez souvent besoin de créer des APIs pour communiquer entre différents systèmes ou pour exposer certaines fonctionnalités de votre application à d'autres applications.
Un cas concret de l'utilisation d'une API REST avec Symfony est lorsqu'un site web nécessite d'intégrer une application mobile. Le backend de l'application web expose une API REST qui peut être consommée par l'application mobile pour récupérer les données nécessaires.
Prerequis
- Connaissances en PHP et dans le développement web
- Symfony 6 ou supérieur installé (https://symfony.com/download)
- Composer (https://getcomposer.org/)
- Un environnement de développement local comme XAMPP, MAMP ou Docker
Concepts fondamentaux
1. Contrôleur (Controller)
Un contrôleur est une classe qui gère les requêtes HTTP et retourne la réponse appropriée. Chaque action du contrôleur correspond à une route spécifique.
Code :
// src/Controller/TaskController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
class TaskController extends AbstractController
{
public function index(): Response
{
return $this->render('task/index.html.twig');
}
}
2. Route (Routing)
Les routes définissent les URL que votre application va gérer et où ces URLs pointent. Symfony utilise le YAML pour définir les routes.
Code :
## config/routes.yaml
app_tasks_index:
path: /tasks
controller: App\Controller\TaskController::index
3. Entité (Entity)
Les entités représentent les données de votre application. Symfony utilise Doctrine comme ORM pour gérer les entités.
Code :
// src/Entity/Task.php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="App\Repository\TaskRepository")
*/
class Task
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $name;
// Getters and setters
}
4. Repository (Repository)
Les repositories sont responsables de récupérer les données des entités à partir de la base de données.
Code :
// src/Repository/TaskRepository.php
namespace App\Repository;
use App\Entity\Task;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Symfony\Bridge\Doctrine\RegistryInterface;
class TaskRepository extends ServiceEntityRepository
{
public function __construct(RegistryInterface $registry)
{
parent::__construct($registry, Task::class);
}
// Custom query methods
}
5. Serializer (Serializer)
Le serializer permet de convertir les entités en données JSON ou XML pour une réponse API.
Code :
## config/packages/serialization.yaml
framework:
serialization:
enable_annotations: true
Mise en pratique : projet fil rouge
Étape 1 : Créer le projet Symfony
Commencez par créer un nouveau projet Symfony :
composer create-project symfony/website-skeleton api-rest-symfony
cd api-rest-symfony
Étape 2 : Installer les dépendances
Installez les dépendances nécessaires pour l'API REST :
composer require doctrine/doctrine-bundle doctrine/orm annotations
composer require symfony/maker-bundle --dev
composer require nelmio/api-doc-bundle --dev
Étape 3 : Créer une entité Task
Créez une nouvelle entité Task :
// src/Entity/Task.php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity(repositoryClass="App\Repository\TaskRepository")
*/
class Task
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $name;
// Getters and setters
}
Étape 4 : Créer un repository pour la table Task
Créez un repository pour la table Task :
// src/Repository/TaskRepository.php
namespace App\Repository;
use App\Entity\Task;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Symfony\Bridge\Doctrine\RegistryInterface;
class TaskRepository extends ServiceEntityRepository
{
public function __construct(RegistryInterface $registry)
{
parent::__construct($registry, Task::class);
}
// Custom query methods
}
Étape 5 : Créer un service pour les tâches
Créez un service pour gérer les opérations CRUD sur les tâches :
// src/Service/TaskService.php
namespace App\Service;
use App\Entity\Task;
use App\Repository\TaskRepository;
use Doctrine\ORM\EntityManagerInterface;
class TaskService
{
private $entityManager;
private $repository;
public function __construct(EntityManagerInterface $entityManager, TaskRepository $repository)
{
$this->entityManager = $entityManager;
$this->repository = $repository;
}
public function findAll(): array
{
return $this->repository->findAll();
}
public function create(string $name): Task
{
$task = new Task();
$task->setName($name);
$this->entityManager->persist($task);
$this->entityManager->flush();
return $task;
}
// Other methods (update, delete)
}
Étape 6 : Créer un contrôleur pour les tâches
Créez un contrôleur pour gérer les routes API REST :
// src/Controller/TaskController.php
namespace App\Controller;
use App\Entity\Task;
use App\Service\TaskService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
class TaskController extends AbstractController
{
private $taskService;
public function __construct(TaskService $taskService)
{
$this->taskService = $taskService;
}
/**
* @Route("/tasks", name="app_tasks_index", methods={"GET"})
*/
public function index(): JsonResponse
{
$tasks = $this->taskService->findAll();
return $this->json($tasks);
}
/**
* @Route("/tasks", name="app_tasks_create", methods={"POST"})
*/
public function create(Request $request): JsonResponse
{
$name = $request->get('name');
$task = $this->taskService->create($name);
return $this->json($task, 201);
}
}
Étape 7 : Configurer les routes
Ajoutez les routes pour le contrôleur TaskController dans config/routes.yaml :
app_tasks_index:
path: /tasks
controller: App\Controller\TaskController::index
methods: [GET]
app_tasks_create:
path: /tasks
controller: App\Controller\TaskController::create
methods: [POST]
Étape 8 : Tester l'API
Vous pouvez tester l'API en utilisant Postman ou curl. Voici un exemple avec curl :
## GET all tasks
curl -X GET http://localhost:8000/tasks
## POST a new task
curl -X POST -H "Content-Type: application/json" -d '{"name":"New Task"}' http://localhost:8000/tasks
Erreurs frequentes et debugging
1. Mauvais : Erreur de syntaxe dans le contrôleur
// ❌ Mauvais
public function create(Request $request): JsonResponse
{
$name = $request->get('name');
$task = new Task();
$task->setName($name);
return $this->json($task, 201);
}
symfony
## ✅ Correct
public function create(Request $request): JsonResponse
{
$name = $request->get('name');
$task = new Task();
$task->setName($name);
return $this->json($task, 201);
}
2. Mauvais : Erreur de connexion à la base de données
## ❌ Mauvais
php bin/console doctrine:schema:update --force
symfony
## ✅ Correct
php bin/console doctrine:schema:update --force
3. Mauvais : Erreur d'autorisation
// ❌ Mauvais
public function create(Request $request): JsonResponse
{
$name = $request->get('name');
$task = new Task();
$task->setName($name);
return $this->json($task, 201);
}
symfony
## ✅ Correct
use Symfony\Component\Security\Core\User\UserInterface;
public function create(Request $request, UserInterface $user): JsonResponse
{
$name = $request->get('name');
$task = new Task();
$task->setName($name);
return $this->json($task, 201);
}
Pour aller plus loin
1. Authentification et autorisation avec JWT
Intégrez l'authentification JWT pour sécuriser votre API.
- https://symfony.com/bundles/FOSJsRoutingBundle/current/index.html
- https://github.com/FriendsOfSymfony/FOSOAuthServerBundle
2. Validation des données
Utilisez Symfony Validator pour valider les données entrantes.
3. Documentation de l'API avec Swagger/OpenAPI
Générer la documentation automatique de votre API avec Swagger/OpenAPI.
Défi pratique
Créez une application simple d'un gestionnaire de tâches où les utilisateurs peuvent créer, lire, mettre à jour et supprimer des tâches. Assurez-vous que l'application est sécurisée avec JWT et qu'elle dispose d'une documentation Swagger générée automatiquement.