Plan du site  
pixel
pixel

Articles - Étudiants SUPINFO

Générer à la volée la documentation de son API Restful avec Symfony

Par Jérémy PERCHE Publié le 03/09/2017 à 13:52:22 Noter cet article:
(0 votes)
Avis favorable du comité de lecture

Ce tutoriel requiert que vous ayez une installation vierge de Symfony 2 ou 3, une base de données MySQL ainsi que composer, et bien évidemment des connaissances nécessaires en PHP, SQL, et Symfony.

Qu’est-ce qu’une API RESTful?

RESTful ou REST est le diminutif de Representational State Transfer. Ceci est un style d’architecture constitué d’un ensemble de conventions et de bonnes pratiques à respecter permettant la construction d’applications (web, intranet ou encore web service). Le standard REST a été créé en 2000 par Roy Fielding dans sa dissertation "Architectural Styles and the Design of Network-based Software Architectures" et utilise les spécifications originelles du protocole HTTP, plutôt que de réinventer une surcouche comme ses concurrents (SOAP, XML-RPC). L’échange est donc basé sur des requêtes client et serveur c’est-à-dire qu’un client lance une requête HTTP, et le serveur renvoie une réponse. En plus de cela, des méthodes qui définissent les requêtes HTTP que le client peut effectuer telles que GET, PUT, POST, DELETE et bien plus encore.

Pour qu’une architecture soit considérée comme REST, elle doit respecter les six contraintes suivantes :

  • Orienté client-serveur, c’est-à-dire que l’interface utilisateur est séparée de celle du stockage des données permettant aux deux d’évoluer indépendamment l’un de l’autre.

  • Sans état, chaque requête d’un client vers un serveur doit contenir toutes les informations nécessaires pour permettre au serveur de comprendre la requête.

  • Mise en cache, le serveur doit donner des informations sur ces réponses pour permettre au client de savoir si celles-ci doivent être conservées dans le futur.

  • Une interface uniforme : identification des ressources, manipulation des ressources à travers des représentations, un message auto-descriptif et l’utilisation d’hypermédia.

  • Un système hiérarchisé par couche.

  • Un code à la demande (optionnel), offrir la possibilité pour les clients d’exécuter des scripts obtenus depuis le serveur.

Aujourd’hui le style d’architecture REST est utilisé par les trois quarts des APIs présentes sur le web et par les plus grands de l’internet comme Google, Amazon ou encore Oracle.

Ainsi dans ce tutoriel, nous utiliserons les bundles FOSRestBundle et NelmioApiDocBundle. Le premier nous servira à mettre en place une API basique très rapidement, tandis que le second va nous permettre de génerer automatiquement et très facilement la documentation de notre API. Ce dernier est devenu au fil du temps un bundle qui n'a aucune équivalence sur la toile, devenant de ce fait incontournable lorsque l'on se lance dans le développement d'une API.

Initialisation et configuration des bundles nécessaires

Dans un premier temps, il faut importer les bundles dans notre projet. Pour cela, nous allons ajouter la ligne suivante dans notre composer.json :

{
    "require": {
        // …
        "friendsofsymfony/rest-bundle": "dev-master",
        "nelmio/api-doc-bundle": "2.x-dev"
    }
}

Mettons ensuite à jour notre composer en tapant la commande suivante dans la console :

php composer.phar update

Puis, il est nécessaire que Symfony les charge dans son noyau. Nous allons donc les ajouter à l’AppKernel.php :

# app/AppKernel.php
<?php

use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;

class AppKernel extends Kernel
{
    public function registerBundles()
    {
        $bundles = [
            // ... D'autres bundles déjà présents
            new FOS\RestBundle\FOSRestBundle(),
            new Nelmio\ApiDocBundle\NelmioApiDocBundle(),
        ];
        // ...
    }

    // ...
}

On a ensuite besoin d’importer les fichiers route de NelmioApiDocBundle. Cela permettra d’accéder aux pages présentes dans le bundle c'est à dire l'interface utilisateur qui expose l'ensemble de la documentation. Pour cela rien de plus simple, il suffit d’ouvrir le fichier routing.yml et d’y ajouter ces quelques lignes :

# app/config/routing.yml
NelmioApiDocBundle:
    resource: "@NelmioApiDocBundle/Resources/config/routing.yml"
    prefix:   /api/doc

Le dernier point de cette configuration est d'indiquer que twig est le moteur de template utilisé par Symfony, indispensable pour le fonctionnement de notre API. Pour ce faire rendez-vous dans le fichier app/config/config.yml :

# app/config/config.yml
framework:
    # ...
    templating:
        engines: ['twig']
#...
nelmio_api_doc: ~

Mise en place de l'API

On passe maintenant à la création de notre API qui sera composée d'une entité Team et d'un controleur TeamControlleur. Durant cette partie, on ne s'attardera pas trop avec des explications, car l'interêt de cet article n'est pas dans la mise en place d'une API mais, plus dans la génération de sa documentation.

Création de l'entité Team

On commence tout d'abord par mettre en place les entités de l'application qui se résume à la seule entité Team.

<?php

// src/AppBundle/Entity/Team.php
namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="team")
 */
class Team
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $name;

    /**
     * @ORM\Column(type="string", length=3)
     */
    private $shortName;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $nationnalite;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $championnat;

    /**
     * @ORM\Column(type="text")
     */
    private $description;

    /**
     * @return mixed
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param mixed $id
     */
    public function setId($id)
    {
        $this->id = $id;
    }

    /**
     * @return mixed
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param mixed $name
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     * @return mixed
     */
    public function getShortName()
    {
        return $this->shortName;
    }

    /**
     * @param mixed $shortName
     */
    public function setShortName($shortName)
    {
        $this->shortName = $shortName;
    }

    /**
     * @return mixed
     */
    public function getNationnalite()
    {
        return $this->nationnalite;
    }

    /**
     * @param mixed $nationnalite
     */
    public function setNationnalite($nationnalite)
    {
        $this->nationnalite = $nationnalite;
    }

    /**
     * @return mixed
     */
    public function getChampionnat()
    {
        return $this->championnat;
    }

    /**
     * @param mixed $championnat
     */
    public function setChampionnat($championnat)
    {
        $this->championnat = $championnat;
    }

    /**
     * @return mixed
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * @param mixed $description
     */
    public function setDescription($description)
    {
        $this->description = $description;
    }
}

On finit tout simplement par mettre à jour le schéma de notre base de données avec la commande suivante dans notre console :

php app/console doctrine:schema:update --force 

Création du contrôleur TeamController

Nous allons maintenant créer notre classe TeamController, contenant l'ensemble des méthodes de notre API. Cette dernière est des plus sommaire puisqu'elle contient uniquement deux méthodes relativement basiques avec tout d'abord getTeamsAction qui retourne l'ensemble des équipes existantes, puis la méthode getTeamAction retournant l'équipe selon l'identifiant passé en paramètre.

<?php

// src/AppBundle/Controller/TeamController.php
namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use FOS\RestBundle\Controller\Annotations as Rest;
use AppBundle\Entity\Team;

class TeamController extends Controller
{
    /**
     * @Rest\Get("/teams", name="app_teams")
     */
    public function getTeamsAction()
    {
        $teams = $this->getDoctrine()->getRepository('AppBundle:Team')->findAll();

        $formatted = [];
        foreach ($teams as $team) {
            $formatted[] = [
                'id' => $team->getId(),
                'name' => $team->getName(),
                'short_name' => $team->getShortName(),
                'nationnalite' => $team->getNationnalite(),
                'championship' => $team->getChampionnat(),
                'description' => $team->getDescription(),
            ];
        }

        return new JsonResponse($formatted);
    }

    /**
     * @Rest\Get("/team/{teamId}")
     */
    public function getTeamAction($teamId)
    {
        $em = $this->getDoctrine()->getManager();

        $team = $em->getRepository('AppBundle:Team')->findOneById($teamId);

        if($team === null)
            return new JsonResponse(['message' => 'Team not found'], Response::HTTP_NOT_FOUND);

        $formatted = [];
        $formatted[] = [
            'id' => $team->getId(),
            'name' => $team->getName(),
            'short_name' => $team->getShortName(),
            'nationnalite' => $team->getNationnalite(),
            'championship' => $team->getChampionnat(),
            'description' => $team->getDescription(),
        ];

        return new JsonResponse($formatted);
    }
}

Génération de la documentation

On va maintenant entrer dans le vif du sujet de cet article en parlant du bundle nelmioApiDocBundle. Ce dernier va nous permettre de générer très rapidement une documentation pour notre API. Pour ce faire, il fournit tout un ensemble d'annotations qui sont interpretées par le bundle pour l'afficher sur l'interface. Parmi ces annotations nous avons :

  • description, qui permet comme son nom l'indique, d'afficher une courte description sur ce que fait cette méthode de l'API.

  • section, permet de grouper les ressources en catégorie.

  • output, le type de sortie associé à la réponse.

  • input, le type de saisie associé à la méthode.

  • parameters, tableau contenant les paramètres de la méthode.

  • tags, permet d'ajouter un tag à une méthode pour indiquer par exemple qu'elle est en beta ou en développement.

  • statusCodes, un tableau contenant les codes d'état HTTP ainsi qu'une description pour savoir quand le statut en question est retourné.

  • headers, un tableau d'en-têtes; Les propriétés disponibles sont: name, description, required, default.

  • requirements, un tableau d'exigences.

  • filters, un tableau de filtres.

  • deprecated, indique si la méthode est obsolète.

  • https, permet d'indiquer si la méthode néccésite l'utilisation du protocole https.

En plus de toutes ces annotations, le bundle offre aussi par le biais de son interface, un endroit pour envoyer des requetes à chaque méthodes de l'API en indiquant les paramètres s'il y en a.

Ainsi, pour l'API de cet article, on pourrait avoir une documentation de ce genre :

// src/AppBundle/Controller/TeamController.php

// ...

class TeamController extends Controller
{
    /**
     * @Rest\Get("/teams", name="app_teams")
     * @ApiDoc(
     *     description="Returns a list of all teams",
     *     output="AppBundle\Entity\Team",
     *     section="Team",
     *     tags={
     *         "stable",
     *     },
     *     statusCodes={
     *         200="Returned when successful"
     *     }
     * )
     */
    public function getTeamsAction()
    {
        // ...
    }

    /**
     * @Rest\Get("/team/{teamId}")
     * @ApiDoc(
     *     description="Returns a team",
     *     output="AppBundle\Entity\Team",
     *     section="Team",
     *     tags={
     *         "stable",
     *     },
     *     statusCodes={
     *         200="Returned when successful",
     *         404="Returned when the team is not found"
     *     },
     *     requirements={
     *         {
     *          "name"="teamId",
     *          "dataType"="integer",
     *          "requirement"="\d+",
     *          "description"="team id"
     *         }
     *     }
     * )
     */
    public function getTeamAction($teamId)
    {
        // ...
    }

}

Conclusion

Nous avons enfin fini la mise en place de la documentation pour notre API RESTful et nous pouvons dès à présent en profiter. C’est maintenant à vous d'adapter le bundle à votre API ainsi qu'à vos propres besoins. Si vous le souhaitez, vous pouvez approfondir encore un peu concernant votre API RESTful en implémentant une authentification JWT (Json Web Token) pour sécuriser la connexion entre les deux parties.

Merci de votre lecture !

A propos de SUPINFO | Contacts & adresses | Enseigner à SUPINFO | Presse | Conditions d'utilisation & Copyright | Respect de la vie privée | Investir
Logo de la société Cisco, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société IBM, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Sun-Oracle, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Apple, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Sybase, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Novell, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Intel, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Accenture, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société SAP, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Prometric, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Toeic, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo du IT Academy Program par Microsoft, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management

SUPINFO International University
Ecole d'Informatique - IT School
École Supérieure d'Informatique de Paris, leader en France
La Grande Ecole de l'informatique, du numérique et du management
Fondée en 1965, reconnue par l'État. Titre Bac+5 certifié au niveau I.
SUPINFO International University is globally operated by EDUCINVEST Belgium - Avenue Louise, 534 - 1050 Brussels