Dans ce TD, nous nous baserons sur le code écrit dans le TD1. Maintenant que nous pouvons publier des messages en récupérant les coordonnées des adresses, nous allons exposer notre propre API, pour permettre aux utilisateurs de publier et de consulter les messages.
Avant d'aller plus loin, nous allons stocker les dates de création des messages. Lancez :
symfony console make:entity
Et ajoutez un champ date
de type datetime
(qui peut être null). Lancez :
symfony console doctrine:schema:update --force
Pour mettre à jour votre base de données.
Ajoutez le constructeur suivant dans Message
pour que la date initiale soit celle de création:
public function __construct()
{
$this->date = new \DateTime();
}
Enfin, ajoutez un message et vérifiez que la date est bien enregistrée.
À l'aide de la commande:
symfony console make:controller
Créez un contrôlleur ApiController
. Ajoutez l'attribut #[Route('/api')]
à la classe. De cette manière,
toutes les routes de ce contrôlleur seront préfixées par /api/
.
C'est ici que nous hébergerons nos endpoints !
Créez tout d'abord un premier endpoint, dont voici les caractéristiques:
/api/messages
GET
La réponse aura cette forme :
{
"messages": [
{
"id": 17,
"text": "Bonjour à tous!",
"date": "2023-01-16T16:14:14+01:00"
},
...
]
}
(La date est ici formatée en ISO 8601)
Conseil: avec Symfony il est possible de construire un tableau PHP $data
et d'utiliser:
return $this->json($data)
Avant d'aller plus loin, nous allons utiliser des outils qui permettront de nous simplifier la tâche. Premièrement, installez :
symfony composer require friendsofsymfony/rest-bundle
Éditez alors config/packages/fos_rest.yaml
de cette façon:
# config/packages/fos_rest.yaml
fos_rest:
view:
view_response_listener: true
format_listener:
rules:
- { path: ^/api, prefer_extension: true, fallback_format: json, priorities: [ json ] }
- { path: '^/', priorities: ['text/html', '*/*'], fallback_format: html, prefer_extension: true }
Et ajoutez l'attribut View
(de FOS\RestBundle\Controller\Annotations\View
) à votre action, qui pourra
devenir :
#[View()]
#[Route('/messages', name: 'app_api')]
public function index(MessageRepository $messagesRepository)
{
return [
"messages" => $messagesRepository->findAll()
];
}
Constatez que les messages sont désormais sérialisés automatiquement !
La sérialisation automatique est très pratique, mais elle expose par défaut tous les champs de notre message, ce qui pourrait être inutile, ou même divulguer des informations que l'on ne souhaite pas.
Pour ce faire, il est possible de définir ce que l'on appelle des groupes de sérialisation.
À l'aide de la documentation, créez un groupe de sérialisation message_basic
qui ne contient
que les informations "basiques" (l'id, le texte et la date), et modifiez votre attribut View
pour
utiliser ce groupe.
Documentation :
Nous allons pouvoir enfin assembler ce que nous avons fait de manière à apporter une première fonction de Géo-chat !
Modifiez le endpoint /api/messages
, de manière à ce que :
address
obligatoire: une chaîne de caractère donnant l'adresse autour de laquelle on souhaite
obtenir les messagesradius
: un rayon (par défaut 2000) en mètres utilisé pour la rechercheLes erreurs suivantes seront gérées:
Elle donneront lieu à des erreurs HTTP de type 400
(Bad request).
Les distances seront fournies dans la réponse, exemple :
{
"results": [
{
"message": {
"text": "Un bonjour du département #iutinformatique"
},
"distance": 386.33058427448344
}
],
...
}
Vous pourrez utiliser la méthode MessageRepository::findClose()
, qui vous aidera à calculer les distances
entre les points.
Vous pouvez utiliser
MapQueryParameter
afin de gérer plus efficacement les paramètres address
et radius
.
Ajoutez un paramètre posted_after
optionnel au endpoint /api/messages
, qui filtre les messages qui
ont été postés uniquement après une date donnée.
Créez un nouveau endpoint permettant de publier des messages :
/api/message
POST
Cet appel créera un message dans la base de données. Pour l'instant, ne vous occupez pas des erreurs, et répondez :
{
"message": {
"id": 34,
"text": "Coucou !",
"date": "2023-01-16T18:15:57+01:00"
}
}
Pour cela, vous utiliserez MapRequestPayload, afin de désérialiser le message reçu en JSON.
Maintenant, nous allons gérer les contraintes suivantes :
text
ne soit pas videaddress
ne soit pas videPour cela :
Message
à l'aide de l'attribut #[Assert\...]
du
validateur de SymfonyImplémentez maintenant un endpoint permettant de mettre à jour un message :
/message/{id}
PATCH
Ce endpoint fonctionnera exactement comme le précédent, mais en mise à jour. Vous êtes invité à factoriser le plus de code possible !
Ajoutez maintenant un endopoint permettant de supprimer un message :
/message/{id}
DELETE
Cet appel détruit le message passé en paramètre. Pour l'instant, notez que :