Mission Apollo, ou comment intégrer GraphQL au sein de VueJS

Le roadshow VueJS s’est arrêté à Paris le 29 juin dernier, et nous étions de la partie.

Dans un précédent article, je proposais un retour sur la conférence d’Eduardo San Martin Morote dédiée aux animations et modules transition et motion de Vue2. Une seconde conférence a particulièrement attiré mon attention, celle de Guillaume Chau, membre de la core team Vue, qui nous a montré son projet Vue Apollo ayant pour but d’intégrer des échanges GraphQL de manière la plus transparente et simple possible au sein d’un projet Vue.

GraphQL, qu’est-ce que c’est ?

 

GraphQL est un ensemble de spécifications proposées par Facebook visant à optimiser et simplifier les échanges client-serveur.
Ces dernières années l’API REST est devenue un standard. Grossièrement, elle consiste à exposer un service pour chaque entité serveur permettant de la récupérer, l’éditer ou la supprimer.

L’inconvénient majeur de REST est que le nombre de services croît à mesure que de nouvelles entités sont ajoutées à un projet. De plus, la récupération ou la mise à jour de plusieurs entités différentes peut vite demander un nombre de requêtes en cascade, à moins de développer des services custom pour s’en charger.

C’est, entre autres, à ce type de problèmes que GraphQL essaie de répondre, en ajoutant au passage un typage fort des données rendant possible l’autocomplétion sur des value objects ou encore la génération automatique de documentation. Ouvert en 2015 par Facebook, qui l’utilise en production, il est depuis utilisé par des grands noms comme Github, Coursera, Dailymotion, 20 Minutes, Paypal ou encore Pinterest.

L’idée de base de GraphQL est de ne proposer que deux interfaces que sont “query” et mutation” qui sont effectuées respectivement en GET et en POST. L’interface “query” permet de récupérer des données, filtrées si besoin, là où l’interface “mutation” permet de modifier des données.

Il existe également une interface “subscription” pour s’abonner à une requête. Autrement dit, à chaque fois que le résultat de cette requête change, on en est notifié.

L’un des principaux avantages est qu’il est possible, en une seule requête, de récupérer plusieurs types de données différentes, là où il faudrait effectuer de nombreuses requêtes en cascade ou développer un service custom avec REST. De plus on ne récupère que les données que l’on souhaite, ce qui réduit le poids des requêtes.

Apollo, qu’est-ce que c’est ?

Apollo est une suite d’outils simplifiant la mise en place de GraphQL au sein d’un projet. Il est composé de trois parties principales :

  • Client : pour effectuer des requêtes et du binding GraphQL avec le serveur
  • Engine : le point d’entrée vers le serveur qui effectue du caching et permet le tracking de performance et d’erreurs.
  • Server : pour ajouter une couche pour transformer une API et un backend REST en GraphQL.

La partie qui nous intéresse ici est la partie client avec Vue-Apollo, qui permet de faire du binding de données client/serveur au sein d’un projet vue. Vue-Apollo gère également la propagation d’événements via websockets.  

Vue-Apollo : GraphQL intégré à VueJS 

Vue-Apollo a donc pour mission d’intégrer GraphQL via Apollo au sein de VueJS de manière simple en demandant le moins de code possible pour l’utilisateur final.   Il existe en ce sens 3 principaux composants qui sont <ApolloQuery><ApolloMutation> et <ApolloSubscribeToMore> et qui reflètent les 3 interfaces GraphQL mentionnées précédemment.   Voici un exemple d’utilisation du composant <ApolloQuery> pour effectuer une requête : 

<ApolloQuery
  :query="require(/graphql/HelloWorld.gql')" 
  :variables="{ name }" 
> 
  <template slot-scope="{ result: { loadingerrordata } }"> 
    <!-- Loading --> 
    <div v-if="loading" class="loading apollo">Loading...</div> 

    <!-- Error --> 
    <div v-else-if="error" class="error apollo">An error occured</div> 

    <!-- Result --> 
    <div v-else-if="data" class="result apollo">{{ data.hello }}</div> 

     <!-- No result --> 
    <div v-else class="no-result apollo">No result :(</div> 
  </template> 
</ApolloQuery> 

Ici, une requête est effectuée sur HelloWorld.gql et - sans une seule ligne de code JavaScript - on affiche un loader, une erreur en cas d’erreur ou le résultat de la requête.  De même, pour effectuer une mutation : 

<ApolloMutation
  :mutation="require('/graphql/userLogin.gql')"
  :variables="{ 
   email,
   password, 
  }" 
  @done="onDone" 
> 
  <template slot-scope="{ mutateloadingerror }">
    <!-- Form --> 
    <input v-model="email" type="email"> 
    <input v-model="password" type="password"> 
    <button :disabled="loading" @click="mutate()">Submit</button> 

    <!-- Error --> 
    <p v-if="error">An error occured: {{ error }}</p> 
  </template> 
</ApolloMutation> 

De la même manière, on désactive ici le bouton de soumission durant l’exécution de la requête. Si une erreur se produit, on l’affiche, et si tout se passe, bien la méthode “onDone” est appelée.  Apollo-Vue permet également de s’abonner à une requête de sorte que si le résultat de celle-ci change (suite à une mutation par un autre client par exemple) l’application puisse en être notifiée.  On peut s’abonner à ces mises à jour soit via JavaScript, soit via le composant <ApolloSubscribeToMore> dans le composant <ApolloQuery> : 

<ApolloQuery :query="..."> 
    <ApolloSubscribeToMore 
      :document="require('../gql/MessageAdded.gql')" 
      :variables="{ channel }" 
      :updateQuery="onMessageAdded" 
    /> 
</ApolloQuery> 

Ici, la requête sera exécutée une première fois puis chaque fois qu’une mutation aura lieu, la méthode “onMessageAdded” sera appelée avec en paramètre l’état précédent et le nouvel état de la requête. 

Conclusion 

Allier la puissance et la simplicité de VueJS et de GraphQL via Vue-Apollo rend une application réactive à moindre effort et en un minimum de code tout en bénéficiant des outils proposés par Apollo, comme Apollo Engine permettant le tracking et le debugging en plus d’un caching de données, ou encore l’outil GraphQL qui permet de tester ses requêtes GraphQL avec un système d’autocomplétion sur les champs d’entités et des remontées d’erreur en live. 

Au final, une fois tout ceci mis en place, le gain de temps n’est pas négligeable par rapport aux autres solutions existantes, alors qu’attendez-vous pour essayer ?