Écrit par Maxim J.
Quésaco 🕵️♂️
GraphQL c’est un langage de requête qui propose une nouvelle façon d’intéragir avec nos données comparé à une approche REST plus classique. Développé par Facebook en 2012, il a gagné en popularité en 2015 lorsqu’il est devenu open source. Aujourd’hui, de nombreuses entreprises comme Tripadvisor, Shopify, Netflix ou GitHub s’en servent.
Nous allons voir la différence entre GraphQL et REST puis comment l’intégrer dans un projet Ruby on Rails.
Pourquoi GraphQL
Avant de parler vraiment de l’utilisation de GraphQL, voyons pourquoi il a été conçu et quels problèmes il cherche à résoudre.
Les APIs REST sont très répandues, elles ont néanmoins quelques problèmes. Les plus notables : surchargement des données (overFETCHING) et le sous-chargement des données (underFETCHING)
- overFETCHING 👆 : Quand on fait une requête à une API REST, il arrive qu’on reçoive plus de données que nécessaire par exemple, si sur la page d’accueil de notre application, on veut juste afficher le nom et l’avatar de l’utilisateur, on va pourtant recevoir toutes les informations associées à cet utilisateur (nom, prénom, email, adresse, téléphone, etc․) Résultat, on se retrouve avec plus de données que ce que nous souhaitons.
- underFETCHING 👇 : À l’opposé, il arrive aussi qu’on soit obligé de faire plusieurs requêtes pour obtenir toutes les données dont nous avons besoin. Par exemple, si on souhaite afficher la page de profil d’un utilisateur, on va devoir récupérer ses informations, puis faire une seconde requête pour obtenir la liste des articles, etc…
GraphQL a été en partie conçu pour contourner ce problème, eh oui GraphQL permet de demander exactement les données qu’on veut, sans superflu. Cela amène plusieurs avantages :
- Diminuer la taille des réponses (amélioration des performances)
- Réduire le nombre de requêtes nécessaires
- Faciliter la tâche des développeurs front
Un unique endpoint
Un autre avantage de GraphQL est l’utilisation d’un endpoint unique, à l’inverse dans une API REST traditionnelle dans laquelle chaque ressource a son propre endpoint (ex : /users
pour nos utilisateurs, /articles
pour les articles). Cela facilite la gestion des routes côté backend… Pour nos amis front, il n’est plus nécessaire d’apprendre tous les endpoint de l’API, on va pouvoir retrouver tout au même endroit.
Comment ça marche ⚙️
Maintenant qu’on a passé en revu les avantages de GraphQL, voyons comment le faire fonctionner avec Ruby on Rails, pour ça, on va utiliser la gem graphql-ruby.
Direction le Gemfile
gem 'graphql'
On installe la gem.
bundle install rails generate graphql:install
Cette commande va nous créer plusieurs fichiers dans notre application. Voici un peu plus de détails sur ceux qui nous intéresse :
app/graphql
: C’est ici qu’on va définir nos types, nos requêtes et nos mutationsapp/controllers/graphql_controller.rb
: C’est le contrôleur qui va gérer les requêtes GraphQLapp/graphql/blog_schema.rb
: C’est le schéma principal de notre API GraphQL, qui définit comment les requêtes et les mutations sont résolues
En guise de projet, nous allons faire un grand classique qui parle à tout le monde… Un BLOG avec :
- Des articles 📝
- Des utilisateurs 👥
- Des commentaires pour nos articles 💬
Le schéma principal
Notre schéma est important pour notre API, il est généré lors de l’installation de GraphQL sur le projet et va nous indiquer la liste des requêtes et les mutations disponibles pour notre blog :
class BlogSchema < GraphQL::Schema query(Types::QueryType) mutation(Types::MutationTYpe) end
Définir un type
La première étape c’est la génération de nos modèles Rails, rien ne change, on fait comme d’habitude.
rails g model User name:string email:string rails g model Article title:string content:text user:references rails g model Comment content:text user:references article:references rails db:migrate
Les Articles sont liés à un Utilisateur et les Commentaires (écrits par un Utilisateur) sont liés à un Article.
C’est ici qu’on change notre manière de faire et que GraphQL entre en piste. On va définir nos types dans app/graphql/types
UserType :
# /app/grahpql/types/user_type.rb module Types class UserType < Types::BaseObject field :id, ID, null: false field :name, String, null: false field :email, String, null: false field :articles, [Types::ArticleType], null: true field :comments, [Types::CommentType], null: true end end
ArticleType
:
# /app/grahpql/types/article_type.rb module Types class ArticleType < Types::BaseObject field :id, ID, null: false field :title, String, null: false field :content, String, null: false field :user, Types::UserType, null: false field :comments, [Types::CommentType], null: true end end
CommentType
:
# /app/grahpql/types/comment_type.rb module Types class CommentType < Types::BaseObject field :id, ID, null: false field :content, String, null: false field :user, Types::UserType, null: false field :article, Types::ArticleType, null: false end end
Définir une requête
C’est bien beau d’avoir nos types, mais comment récupérer les données ? C’est là qu’interviennent les requêtes. Nous allons les définir dans le fichier app/graphql/types/query_type.rb
Ici, nous allons :
- Récupérer la liste de tous les Articles
- Récupérer un Article
- Récupérer les Commentaires liés à un Article module Types
class QueryType < Types::BaseObject# Récupérer tous les articles field :articles, [Types::ArticleType], null: false do description "All articles" end def articles Article.all end # Récupérer un article field :article, Types::ArticleType, null: false do description "Find an article by ID" argument :id, ID, required: true end def article(id:) Article.find(id) end # Récupérer les commentaires d'un article field :comments, [Types::CommentType], null: true do description "Find comments by article ID" argument :article_id, ID, required: true end def comments(article_id:) Comment.where(article_id: article_id) end
end
end
Tester tout ça 🧪
Maintenant que nos modèles et requêtes sont en place, parlons de GraphiQL pour tester nos requêtes. Ajoutons la gem graphiql-rails
à notre projet, lançons le serveur, ouvrons notre navigateur préféré (🔥🦊) et rendons-nous sur localhost:3000/graphiql
.
Définir une mutation 🧬
Maintenant qu’on peut afficher nos articles, on souhaite aussi pouvoir interagir avec, pour notre exemple ça va se traduire en permettant de créer un article.
# /app/graphql/mutations/create_article.rb module Mutations class CreateArticle < BaseMutation argument :title, String, required: true argument :content, String, required: true argument :user_id, ID, required: true type Types::ArticleType def resolve(title:, content:, user_id:) user = User.find(user_id) raise GraphQL::ExecutionError, "User not found" unless user Article.create!( title: title, content: content, user: user ) end end end
Un autre exemple, voici une mutation pour ajouter un commentaire à un article.
# /app/graphql/mutations/create_comment.rb module Mutations class CreateComment < BaseMutation argument :article_id, ID, required: true argument :content, String, required: true argument :user_id, ID, required: true type Types::CommentType def resolve(article_id:, content:, user_id:) user = User.find(user_id) raise GraphQL::ExecutionError, "User not found" unless user article = Article.find(article_id) Comment.create!( content: content, article: article, user: user ) end end end
Avec nos 2 nouvelles mutations, pour qu’elles fonctionnent avec GraphQL, il faut ensuite les ajouter dans notre fichier app/graphql/types/mutation_type.rb
module Types class MutationType < Types::BaseObject field :create_article, mutation: Mutations::CreateArticle field :create_comment, mutation: Mutations::CreateComment end end
De la même manière, nous pouvons tester à l’aide de notre gem graphiql
la création d’un article :
Conclusion
Nous avons vu comment définir des types, créer des requêtes et des mutations et comment les tester depuis le navigateur avec GraphiQL. Nous voilà avec notre blog utilisant GraphQL. Tu devrais maintenant comprendre son intérêt et comment l’utiliser avec Ruby on Rails 🎉