Pourquoi (et surtout comment) Le Figaro a choisi la technologie GraphQL pour moderniser ses API

Construire Le Figaro
11 min readNov 30, 2022

--

Pour moderniser nos API, nous avons décidé il y a quatre ans de miser sur une technologie innovante: GraphQL. Ce qui a poussé nos équipes à faire des choix essentiels en termes d’écosystème, d’outils, de stratégie de cache. Retour d’expérience.

En janvier 2018, Le Figaro a souhaité investir dans la modernisation de son architecture en misant sur une technologie moderne et innovante, bien que récente pour l’époque : GraphQL (pour Graph Query Language), un langage de requêtes développé par Facebook en 2012 pour ses propres besoins avant d’être publié comme projet open-source en 2015. Pour comprendre ce choix technologique, il faut d’abord que nous vous racontions le contexte et les enjeux qui nous ont amené à ré-imaginer notre écosystème d’APIs.

Le Figaro, plus ancien titre de presse quotidienne en activité, est le leader français de son secteur en audience numérique avec plus de 38 millions de visiteurs uniques par mois, selon le classement Médiamétrie. Près de 30 thématiques sont ainsi proposées aux lecteurs, sur des supports allant des textes aux vidéos en passant par les stories, les lives et les podcasts.

Pour chacune de ces thématiques, nous avons développé des dizaines d’APIs REST : API de contenus publiés depuis notre CMS, API vidéos, API résultats sportifs, API programmes télé, …, mais aussi des APIs portants des données moins visibles pour nos lecteurs telles que la configuration du paywall par thématique ou la configuration des CTAs permettant de proposer des abonnements à nos lecteurs.

Nous avons choisi très tôt d’adopter une architecture orientée services (SOA) et d’organiser ces données dans différentes APIs responsables de leurs traitement. Au delà des aspects techniques (maintenance, fiabilité, évolutivité, …), cela nous a également permis d’organiser les équipes pour optimiser au mieux le Time-To-Market et d’augmenter notre agilité en travaillant simultanément sur des thématiques fondamentalement différentes.

Avant GraphQL: des modifications et des évolutions complexes

Nous ne regrettons pas d’avoir choisi ce type d’architecture. Mais alors que notre stratégie était de ré-internaliser les fronts de certaines de nos marques (opérées par des tiers, lors d’acquisitions par exemple), et d’initier l’industrialisation de notre stack front web et mobile, force était de constater que cette architecture commençait à nous poser quelques difficultés.

D’abord, beaucoup de règles métiers étaient ré-implémentées en permanence sur l’ensemble de nos fronts : l’intégration d’une marque dans notre stack nous contraignait à refaire les mêmes développements, et une évolution ou un changement ne pouvait pas être distribué facilement entre nos applications fronts et mobiles (Le Figaro / Figaro Madame / TV Magazine, … ).

Ensuite, nos applications web clientes pouvaient se retrouver à faire des dizaines d’appels HTTP pour construire une seule page, bien souvent de façon séquentielle même si nous en avions parallélisé un maximum de façon à optimiser au mieux nos performances. D’ailleurs, pour des raisons d’optimisation des performances de nos applications mobiles, nous avons parfois dû développer des endpoints spécifiques afin de réduire le poids des données (pour éviter l’over-fetching) et d’en agréger un maximum pour s’épargner de nombreux appels HTTP couteux en mobilité. Les équipes back-end se retrouvaient donc à passer du temps à maintenir plusieurs endpoints REST plutôt que de produire de nouvelles fonctionnalités. Cela pouvait donc impacter les roadmaps des équipes et cela rendait la maintenance (et la fiabilité) de APIs concernées plus compliquée dans le temps.

Enfin, certaines APIs étaient devenues complexes, parfois vieillissantes, et ne possédaient pas toujours d’homogénéité / de normalisation au niveau du nommage et du typage. Par exemple, en fonction des API, une date pouvait être nommée de manière différente (modified vs modified_at vs modifiedAt), avec un typage également différent (string vs DateTime ISO 8601 vs integer). La documentation ou encore la méthode d’authentification pouvaient varier d’une API à l’autre. Certaines attendaient une authentification HTTP “Basic”, d’autres un token (JWT, ou autre). Puisque ces APIs étaient consommées directement par plusieurs applications clientes (parfois de façons différentes), leurs modifications ou évolutions pouvaient devenir complexes.

Schéma — simpliste — des flux de communication que nous avions à l’époque

L’implémentation de GraphQL et ses défis

Au lieu de refactoriser toutes ces APIs, voir de re-construire toute notre architecture, nous avons alors envisager de positionner une passerelle d’API (ou API Gateway) pour fournir une interface (et un protocole) unique aux applications clientes afin d’obtenir des données à partir de plusieurs sources. Cela nous permettrait d’une part de répondre aux problèmes précédemment mentionnés, et d’autre part de pouvoir faire évoluer les APIs sous-jacentes “legacy” à notre rythme.

Cela nous a amené à initier des Proofs Of Concept afin d’explorer d’autres manières d’accéder à nos données et de les manipuler, en utilisant la technologie GraphQL.

L’utilisation d’une passerelle d’API avec GraphQL était alors un concept relativement nouveau — et qui est d’ailleurs devenu très populaire ces derniers temps — mais qui nous paraissait de prime abord répondre à nos problématiques.

GraphQL est un langage de requête qui permet d’échanger des données entre un client et un serveur. Il est défini par une spécification et s’inscrit comme un nouveau standard dans le développement d’APIs. La particularité de GraphQL est que la structure de la réponse du serveur est fixée par le client. C’est le client qui décide des champs qu’il souhaite pour chaque objet. GraphQL répond donc à une de nos problématiques : l’over-fetching, et donc la maintenance de plusieurs endpoints REST, pour nos applications mobiles.

Ce langage étant fortement typé, nous pouvons donc facilement résoudre une autre de nos problématiques : la normalisation de données. Nous avons donc documenté l’ensemble des propriétés de nos API REST et commencé à imaginer les différents types dont nous avons besoin pour construire notre schéma GraphQL.

Par ailleurs, nous pouvons centraliser certaines règles métiers clientes et agréger de façon transparente les données de plusieurs APIs. Cette API sera l’unique source de données pour nos applications clientes. Nous pouvons donc abstraire les APIs sous-jacentes et donc masquer leurs évolutions ou leurs dettes techniques.

L’équipe a cependant été confrontée à certaines problématiques.

Schéma — simpliste — de la vision cible que nous avions à l’époque

Choisir le bon écosystème

En 2018, l’équipe technique du groupe Figaro est majoritairement composée de développeurs PHP / Symfony.

C’est donc avec ces technologies que les développements ont commencé et que les premières limites ont été atteintes, à la fois au niveau de l’écosystème GraphQL en PHP qui n’était que peu développé à ce moment là (bien que certaines implémentations étaient particulièrement intéressantes, telles que webonyx/graphql-php), mais aussi de par la nature du langage PHP.

Nous avions besoin de pouvoir interroger des dizaines d’APIs en parallèle de façon à résoudre une requête GraphQL le plus rapidement possible, et cela s’est avéré bien plus complexe qu’il n’y paraissait sans utiliser un environnement nous permettant d’exécuter des opérations asynchrones .

PHP ne dispose pas nativement d’APIs HTTP asynchrones. Plusieurs approches à base de Promise existent (client HTTP Guzzle, runtimes PHP “alternatifs” comme ReactPHP ou AmpPHP), mais l’impact fort des Promise sur l’intégralité de la callstack (voir “what color is your function ?”) les rendaient incompatibles avec les librairies GraphQL php du moment (ce point serait probablement réévalué différemment aujourd’hui : la librairie webonyx a entretemps ajouté des adapteurs pour diverses APIs de Promise, et l’introduction des Fibers en PHP 8.1 pourrait à l’avenir simplifier radicalement la coexistence d’APIs synchrones et asynchrones).

Cela nous a alors amené à étudier en parallèle un autre écosystème plus adapté à l’exécution d’opérations de façon asynchrone mais également où la communauté GraphQL était la plus développée à ce moment là : Node.JS.

La richesse de l’écosystème GraphQL Node.JS nous a conduit à la conclusion qu’une approche PHP restait pertinente pour exposer une surcouche GraphQL sur une API ou un CMS PHP existant (Drupal, API Platform…), mais était difficilement justifiable pour construire notre GraphQL API Gateway s’interfaçant avec tous nos services externes.

Le choix de cet écosystème nous a amené à faire monter en compétence certains développeurs PHP désirant évoluer sur cette technologie, mais également à recruter certains profils spécialisés afin de nous apporter leurs expertises sur ce domaine.

Choisir les bons outils

Les premières itérations nous ont amenés à utiliser le framework Apollo GraphQL (version 1 à cette époque) car celui-ci offrait un écosystème et une suite d’outils intéressants : Apollo Client pour faciliter le requêtage HTTP de nos consommateurs et Apollo Engine pour le monitoring des requêtes.

Après quelques phases de développements, et la mise en place de notre stratégie de tests (que nous vous expliquons dans notre précédent article ) nous nous sommes rendu compte que l’écosystème Apollo n’était pas totalement adéquate :

  • Apollo Engine, n’était pas beaucoup plus intéressant que ce que nous avions déjà mis en place en terme d’observabilité de nos applications.
  • Apollo server est une très bonne librairie, mais nous est apparu comme une “black box” au cours des phases de développement, dès lors que nous avons souhaité personnaliser certains éléments.
  • Apollo Client est une librairie intéressante mais non disponible pour nos consommateurs PHP (pas de librairie officielle). De plus, il nous paraissait complexe, voir impossible, d’imposer une librairie HTTP à l’ensemble de nos clients.

Toutes ces raisons nous ont poussé à revoir l’implémentation de notre serveur GraphQL et opté pour express-graphql, qui nous est apparu comme le compromis parfait, en alliant personnalisation et meilleure performance.

Choisir une bonne stratégie de cache

Lors d’évènements ou d’actualités importantes, nos services supportent l’affluence de plusieurs centaines de milliers d’utilisateurs en simultané grâce à notre stratégie de cache HTTP basée sur plusieurs niveaux (Varnish, CDN). Nous avons d’ailleurs beaucoup investi ces dernières années dans le développement d’un système de cache HTTP nous permettant d’obtenir des TTL relativement longs dans l’ensemble de nos services et ce jusqu’au front tout en ayant la capacité d’invalider toute la chaîne rapidement lors de mises à jour.

Or, avec GraphQL, il n’est pas nécessairement naturel d’utiliser ce type de cache HTTP :

  • D’une part, dans la mesure où la structure de la réponse du serveur est fixée par le client, il pourrait y avoir tellement de combinaisons possibles que le cache HTTP serait inutile. Il nous a donc fallu réfléchir à une solution permettant de normaliser la façon d’interroger notre API, du moins sur l’environnement de production, de façon à pouvoir mettre ces réponses en cache.
  • D’autre part, les requêtes clientes sont envoyées en POST au serveur, ce qui nous aurait contraints à revoir certaines choses que ce soit au niveau de notre CDN (Akamai) ou encore au niveau de Varnish. Nous souhaitions pouvoir interroger cette API en utilisant la méthode GET. (Note : ce point pourrait être ré-évalué aujourd’hui lors d’un PoC, Akamai proposant maintenant des fonctionnalités de caching GraphQL)

Grâce à notre exploration du framework Apollo, nous avons découvert le mécanisme de persisted queries : plutôt que d’envoyer l’ensemble de la requête en POST, le client envoi un identifiant de requête en GET connu du serveur (par exemple, un hash de la requête GraphQL), dont la réponse est mise en cache en retour. Ce mécanisme nécessitant la libraire Apollo Client pour fonctionner côté front, et notre écosystème front étant principalement développé en PHP, nous avons dû le réadapter afin de pouvoir s’en abstraire.

Nous avons donc ré-implémenté cette fonctionnalité d’Apollo de façon à permettre à l’ensemble de nos clients d’enregistrer leurs requêtes GraphQL et récupérer en retour un identifiant qu’ils peuvent par la suite utiliser pour interroger l’API (processus qui se déclenche dans les différentes étapes de build/déploiement).

En capitalisant sur notre stratégie de cache HTTP en place, nous avons pu développer une passerelle d’API capable d’absorber de très fortes charges.

Jusqu’à 10 millions de requêtes backend

En mars 2018, la phase exploratoire nous a convaincue que la technologie GraphQL répondait parfaitement aux problématiques auxquelles nous faisions face. Nous avons donc décidé de renforcer l’équipe, composée d’un tech lead et de deux développeurs.

Les développements se sont poursuivis jusqu’à Septembre 2018, date de la première mise en production de l’API.

Il se trouve que cela coïncidait avec le début des développements de notre front AMP industrialisé (pour l’ensemble de nos marques). Nous avons donc naturellement décidé d’utiliser l’API GraphQL.

Les premiers retours de l’équipe étaient excellents : l’expérience de développement (DX) est nettement améliorée avec l’utilisation de GraphQL. Cela a d’ailleurs été l’occasion pour l’équipe de développer de l’outillage PHP GraphQL pour nos fronts, et en particulier une bibliothèque PHP permettant de créer des requêtes GraphQL via un Query Builder, comme nous l’aurions fait pour interroger une base de données.

Par ailleurs, la direction technique a également noté une nette diminution du Time to Market. En moins de 2 mois, ce projet était en production. La découverte des éléments nécessaires au front, la documentation associée à chaque resolver, et la simplicité d’usage de cette API ont en particulier permis cela.

Suite aux résultats obtenus lors du développement de ce premier front, nous avons alors décidé de porter l’ensemble de nos sites et applications mobiles sur GraphQL en 2019. En octobre 2019, le site principal du Groupe Figaro, Le Figaro.fr , qui concentre le plus fort du trafic, consommait à son tour la passerelle d’API, avec une refonte graphique totale.

Aujourd’hui, la quasi-totalité de nos marques sont gérées par une stack front industrialisée (c’est à dire qu’une même base de code porte l’ensemble des marques, Le Figaro, Madame Figaro, Le Particulier, TV Mag, …). Cela représente pour l’API GraphQL plus de 10 millions de requête backend par jour et plus de 30 millions d’appels à notre CDN par jour, avec un taux d’accès au cache (HIT ratio) de l’ordre 70% à plus de 90% selon les clients.

Une API en perpétuelle évolution

Durant cette longue période d’industrialisation de nos fronts, le projet de passerelle d’API n’a jamais été à l’arrêt. De la mise en place des mutations, pour consolider la notion d’interlocuteur unique pour nos consommateurs, à la migration vers TypeScript, pour bénéficier d’un typage fort à la fois côté GraphQL et à la fois côté code: le projet évolue en permanence.

Son évolution passe également par l’agrandissement de son périmètre métier. Des nouvelles sources de données sont venues s’y ajouter, pour répondre aux besoins de nouveaux projets, comme notre écosystème Le Figaro Voyage ou l’application Le Figaro Cuisine qui partage les données du site Madame Figaro.

Nous avons également profité de ces 4 dernières années pour aborder la dette technique des APIs concernées et les faire évoluer de manière transparentes pour tous les clients : nous comptons maintenant plus d’une vingtaine d’API majeures fédérées dans notre passerelle.

Le choix d’utiliser GraphQL pour construire notre API Gateway s’avère toujours aujourd’hui un choix pertinent et payant. L’interaction avec les différentes équipes est fluide, et les évolutions se font assez naturellement.

L’augmentation du nombre de sources de données nous amène aujourd’hui à repenser l’architecture de l’API GraphQL, représentant une base de code importante et des schémas divers et variés. La migration opérée vers Kubernetes cette année nous offre la possibilité de réfléchir à restructurer notre passerelle en plusieurs services GraphQL grâce à des solutions comme le Schéma Stitching ou Apollo Fédération. Nous multiplions donc les PoCs en ce sens et continuons à investir dans cette technologie.

Par Brice Mancone et Mehdi Beldjilali avec Chi Thanh Bui et Yves Chedemois

N’hésitez pas à nous faire des retours sur cet article où à nous faire part de vos questions dans les commentaires. Toute l’équipe sera d’ailleurs ravie d’échanger / de débattre avec vous sur tout ou partie de nos choix.

--

--

Construire Le Figaro

Les projets, défis techniques et réalisations des sites et applications du Figaro