PrestaConcept
Nos réalisations
Nos métiers
  • Découvrez nos métiers
  • Développement web sur mesure

    Nous développons en méthode agile des back sous le framework PHP Symfony, des front en Angular.

  • Maintenance d'applications

    Maintien en condition opérationnelle de votre plateforme Symfony.

  • Expertise Symfony

    Coaching, formation, audit et conseil.

  • Hébergement et Infogérance

    Une expertise de l'hébergement depuis plus de 15 ans et l’infogérance de centaines de machines en production actuellement.

  • Qui sommes nous
  • Découvrez Prestaconcept
  • PrestaConcept

    Notre histoire, nos convictions, notre vision... Découvrez ce qui nous anime !

  • L'équipe

    Plus de 15 ans minimum d'expérience sur Symfony.

  • Nos engagements RSE

    Une société engagée pour un numérique responsable.

  • Nos convictions

    Co-construction, transparence.. Les principes qui guident nos collaborations !

  • Nous rejoindre

    Envie de nous rejoindre ? Consultez nos offres !

  • Blog
    J'ai un projet Nous contacter
    J'ai un projet Nous contacter Menu
    • Accueil
    • Blog
    • Tech
    • Il était une fois l'API

    Blog

    Il était une fois l'API

    API
    Alain Flaus
    Alain Flaus Développeur expert Symfony
    Publié le jeudi 13 mars 2025

    Petite histoire de l'évolution, du POC jusqu'à la V1.

    Bienvenue, installez-vous, prenez un café et laissez-moi vous conter notre aventure.

    Prestaconcept est historiquement une société spécialisée dans le développement d'applications Symfony. Toutefois, le marché est en constante évolution, de nouveaux besoins font leur apparition et remettent en cause les paradigmes établis.
    En l'occurrence, depuis quelques années, la place de plus en plus importante des applications mobiles, angular, react, autre webapps et consort nous ont forcées à adapter l’architecture de nos projets. Et pour nous autres développeurs backend cela s’est traduit par la nécessité de développer des APIs (ce qui personnellement n’est pas pour me déplaire).

    Dans cet article, je vous propose de retracer notre démarche et de vous présenter le résultat de nos pérégrinations.

    Un peu de vulgarisation.

    Déjà, qu'est-ce qu'une API ?

    La définition dit, API (Application Programming Interface) : Ensemble de règles et d’outils qui permettent à différentes applications ou systèmes de communiquer entre eux.

    Effectivement dans notre cas, on tente de faire communiquer des applications back Symfony avec des applications front angular ou mobile.

    Dans quel cas on utilise une API ?

    Dans notre quotidien, en tant qu’utilisateur, on consomme déjà des APIs sans y faire attention. À quelques exceptions près, la majorité des applications installées sur nos smartphones échangent des données avec un serveur.
    Quant au milieu professionnel, c’est assez courant aussi. Il n’est effectivement pas rare de devoir interagir avec des services tiers, que ce soit pour récupérer ou transmettre des données. Mais aussi pour profiter des fonctionnalités fournies par un service tier comme la signature électronique ou le push de notification par exemple. Si l'on parle d'API au sens large, on pourrait considérer les fichiers csv échangés via SFTP qui restent encore très/trop présents mais, aujourd'hui, on fait plutôt référence aux APIs HTTP au format json.

    R&D Solutions existantes

    Lorsque le besoin d’occuper le rôle de fournisseur d’une API s’est présenté, il a fallu trouver une solution technique. Notre démarche a été de commencer par regarder les solutions existantes que ce soit pour les adopter ou s’en inspirer.

    On a retenu et expérimenté trois solutions, elles même basées sur Symfony : ApiPlatform, FOSRestBundle et SyliusResourceBundle. Après une phase de R&D, chacune de ses solutions a pu être éprouvée sur un projet jusqu’en production et confrontée à des besoins clients concrets.

    Elles ont par ailleurs toutes permis de répondre avec plus ou moins de facilité aux besoins de nos clients. Je ne reviendrai pas en détail sur chacune d’entre elles, chacune possède une approche différente avec les avantages et inconvénients que cela implique :

    • Une courbe d’apprentissage plus ou moins longue.
    • Une intégration légère ou structurante voire invasive. Que ce soit sur un nouveau projet ou la reprise d’un existant.
    • Un gain de productivité pour les cas nominaux, mais parfois un surplus de complexité pour les besoins spécifiques.

    On peut aussi citer en vrac : la dépendance aux entités doctrine, la configuration d’attribut à rallonge, le support ou non des DTOs, le temps passé dans les (de)normalizer, etc.

    À noter :

    • Ceci est un constat que l’on a établi suite à nos expérimentations, mais ces solutions ont continué d'évoluer et peut-être comblés certains aspects qui nous ont alors fait défaut. On garde d’ailleurs toujours un œil sur les nouvelles versions de ces dernières pour challenger nos choix.
    • On a aussi jeté un œil à des solutions un peu plus éloignées de notre domaine d'expertise comme GraphQL mais le changement de paradigme n’était pas en adéquation avec notre besoin.

    Une solution adaptée à nos usages ?

    Malheureusement, même après plusieurs essais, force est de constater qu'aucune de ses solutions ne nous convenait pleinement. S’est alors posé la question d’une implémentation maison avec tous les avantages et inconvénients que cela implique (investissement, maintenance, documentation, etc.).

    Première étape, définir le besoin. Qu'est-ce qu'une API du point de vue technique ?

    • Des paramètres d'url.
    • Un payload json en entrée.
    • Un payload json en sortie.
    • Entre l'entrée et la sortie, un controller accessible via une route.
    • N'oublions pas la documentation.

    Si le controller pouvait nous indiquer ce qu'il attend en entrée et nous retourne en sortie, on aurait toutes les infos centralisées au même endroit.

    Finalement, ça ne parait pas si inaccessible.

    On doit pouvoir transformer les données de la “Request” en DTOs (des Query pour la lecture, des Command pour l’écriture). De même pour générer les DTOs qui constituent la “Response”. Les controllers et routes sont gérés par Symfony. Quant à la documentation, c’est toujours fastidieux, mais pourtant indispensable. Et c'est d’autant plus compliqué de la maintenir dans le temps. Une génération automatique, ça serait bien.

    Aussi, on a beaucoup trop de principes et d’acronyme en informatique, mais il y en a quand même un que j'affectionne particulièrement, KISS (Keep It Simple, Stupid). Mangez-en, c’est bon pour la santé des développeurs !

    C’est facile à dire, mais dans le cas présent ça signifie quoi ?

    • On ne réinvente pas la roue, on utilise au maximum les outils et features fournis par le framework.
    • Le plus simple possible à installer et mettre à jour. Ce qui implique, peu ou pas de dépendance trop structurante (notamment pour la reprise d'un projet existant). Et puis, qui n’a pas déjà rencontré des difficultés lors d’une montée de version d’un projet à cause de ses dépendances ?
    • La roadmap : d'abord un POC qu'on viendra étoffer après usage.

    Notre besoin étant défini, il a fallu faire des choix d’implémentation et commencer la création d’un POC.

    En quatre ans, nous avons eu quatre itérations de notre solution allant du POC jusqu’à une V1 actuelle. Chaque version ayant été utilisée sur des projets jusqu’en production, nous avons pu à chaque fois affiner l’implémentation et adopter de nouvelles pratiques et fonctionnalités notamment fournies par Symfony.
    Au final, la version actuelle est plus simple, plus épurée et plus flexible que la version initiale et l’équipe en est plutôt satisfaite.

    L’implémentation

    Nous allons voir point par point comment nous avons répondu au besoin précédemment énoncé.

    Un périmètre contrôlé :
    Il nous paraissait impossible d’implémenter une solution hyper générique qui permette de répondre à tous les besoins sans risquer l'usine à gaz dont une majorité des fonctionnalités serait à usage unique. Finalement la structure de base de Symfony, une Request, une Route, un Controller et une Response c’est très bien.
    Venons simplement ajouter la notion de DTOs qui représenteront nos entrées/sorties et serviront de référence pour générer la documentation.

    Transformer la Request en DTO :
    Dans notre POC, un ArgumentResolver qui a depuis été remplacé au profit d’une fonctionnalité implémentée dans Symfony 6.3 à savoir : Mapping Request Data to Typed Objects. Elle vient avec les attributs #[MapRequestPayload] et #[MapQueryString] qui répondent à notre besoin alors pourquoi s’en priver.

    La Response :
    Pour cette partie, de simples classes PHP qui représentent le modèle de données à renvoyer ainsi que des Factory pour les constituer. On utilise parfois des fonctions statiques, mais on est trop vite limités notamment lorsqu’on a besoin d’utiliser un service pour des calculs ou agréger des données de plusieurs entités par exemple.
    Dans la majorité des cas le format de sortie sera du json. Notre DTO est sérialisé par un listener SerializeResponseListener.
    On a aussi quelques outils en parallèle comme un listener qui permet d’enrichir les headers de la Response.

    Exemple de controller :

    // BlogPostController.php
    
    #[Route('/blog/posts', options: ['api_group' => 'BlogPost'])]
    final class BlogPostController extends AbstractController
    {
        /**
         * @return ListItems<BlogPostResponse>
         */
        #[Route(name: 'api_blog_post_list', methods: [Request::METHOD_GET])]
        public function list(
            #[MapQueryString] BlogPostQuery $query,
            BlogPostRepository $blogPostRepository,
        ): ListItems {
           //...
        }
    }
    

    Documentation auto-générée :
    Ici aussi, on n'a pas cherché à réinventer la roue, NelmioApiDocBundle le fait très bien. On l’a simplement enrichi avec quelques Describer pour supporter nos DTOs, les ArrayShape et autres Generics.
    Récemment, nos développeurs front ont expérimenté la génération automatique de leur modèle à partir de la documentation (avec Hey API). Après tout, pourquoi faire le travail deux fois. Le choix de l'outil n’est cependant pas définitif, mais la documentation était suffisamment robuste pour que cela fonctionne.

    api_doc.png

    Simplicité :
    A l’heure actuelle, notre solution s’appuie sur des concepts de base qui viennent avec Symfony et ne représentent finalement qu’un ensemble d'une vingtaine de classes à peine.

    Besoin émergent :
    Ce n’était pas prévu initialement, mais à l’usage un petit manque s'est fait sentir.
    En effet, pour garantir la simplicité de notre approche, nous avons fait des concessions, dont le choix de ne pas rendre le tout entièrement générique. Comme dit précédemment, on voulait éviter le cauchemar de l’usine à gaz qui supporte tous les cas d’usages possibles, mais aux prix d’une complexité exponentielle et qu’on exploite finalement assez rarement.

    L’un des effets secondaires, c’est que l’on se retrouve à écrire quand même pas mal de code dont pas mal de CRUD.
    L’avantage, c’est que ce code est très simple alors pourquoi ne pas le générer ?
    Là aussi, Symfony nous vient en aide avec un outil de génération très pratique, SymfonyMakerBundle. Ce dernier est encore amené à évoluer mais, le premier jet remplit déjà son office.

    bin/console make:api:crud Blog
    

    Et maintenant ?

    Maintenant, il est temps de conclure, je crois.
    Ah peut-être une dernière précision. Comme vous l’aurez remarqué, je parle de “solution” depuis le début parce que notre petite création n’a toujours pas été nommée. En l’état il s’agit d’un ensemble de classes que l’on transmet. L’une des prochaines étapes sera surement d’en faire un package à part entière et de lui trouver un nom.

    Mes remerciements aux contributeurs des projets que j’ai cités au cours de l’article.
    Aussi un remerciement particulier à notre dresseur de yōkai qui est à l’initiative du POC.

    En attendant la suite, j’espère que notre démarche vous aura intéressé, peut-être y avez-vous retrouvé des éléments qui ont fait écho à votre propre expérience.

    Merci pour votre attention.
    La suite, au prochain épisode !

    Blog

    Pour continuer votre lecture ...

    Tech

    Retour sur le SymfonyLive Online French Edition 2021

    Par Benoit Jouhaud, Matthieu Crinquand, Alain Flaus et Benoit Leveque 15/04/2021

    Croissant virtuel et chacun son café ! C'est ainsi que démarre l'édition 2021 du Symfony Live Online.

    Lire la suite
    Tech

    Le composant workflow de Symfony

    Par Alain Flaus 11/01/2018

    Le composant Workflow est encore récent. Il n'est pas le plus connu, mais gagne à l'être.
    Petit aperçu des possibilités, exemples à la clé, et proposition d'améliorations.

    Lire la suite
    Tech

    Une crontab sous stéroïdes

    Par Yann Eugoné 03/10/2024

    Proposition d'une alternative aux traditionnelles crontabs, dans un projet Symfony

    Lire la suite

    Vous avez un projet Laravel ?

    Nous sommes spécialisés en Symfony, et grâce à Web^ID, l’agence sœur du groupe Agile Invest, nous couvrons aussi toute l’expertise Laravel.

    Découvrir Web^ID

    Une question, un projet ?
    Planifiez un échange avec nous !

    Choisissez votre date
    PrestaConcept - Groupe Agile Invest
    5, imp. Morel, 69003 Lyon +33 (0)4 78 54 45 45
    Suivez-nous
    Ecoindex B

    Ce site internet est un site basse consommation. En savoir plus sur l'Ecoindex

    Nos réalisations

  • Logiciel de mise en conformité réglementaire
  • Application de suivi de production des centrales éoliennes
  • Outil d'aide à la décision
  • Portail client
  • Nos métiers

  • Développement sur-mesure
  • Reprise d'application Symfony
  • Expertise Symfony
  • Hébergement & Infogérance
  • Qui sommes-nous

  • PrestaConcept
  • Groupe Agile Invest
  • L'équipe
  • Engagement RSE
  • Blog

  • Tech
  • Méthodologie
  • PrestaConcept
  • RSE
  • © 2025 PrestaConcept
    Mentions légales Politique de confidentialité 🍪
    Retour en haut de page