Fermer

août 7, 2019

Une introduction à GraphQL: schéma, résolveurs et plus


Dans cet article, je présente quelques concepts fondamentaux de GraphQL et montre comment créer un serveur répondant à deux opérations de requête.

GraphQL est de plus en plus adopté comme moyen de créer et de consommer des API Web. GraphQL est une spécification qui définit un système de types, un langage de requête et un langage de schéma pour votre API Web, ainsi qu'un algorithme d'exécution indiquant comment un service (ou un moteur) GraphQL doit valider et exécuter des requêtes sur le schéma GraphQL. C'est sur cette spécification que sont construits les outils et les bibliothèques permettant de créer des applications GraphQL.

Dans cet article, je vais vous présenter quelques concepts GraphQL mettant l'accent sur le schéma GraphQL, le résolveur et le langage de requête. Si vous souhaitez suivre, vous avez besoin de connaissances de base en JavaScript (en particulier les fonctions de flèche dans ES6) et Node.js. Sans plus tarder, commençons à configurer notre environnement de développement.

Création du projet

Nous allons créer un serveur GraphQL qui répondra aux demandes d’exécution des différents types d’opérations dans GraphQL. Ouvrez votre terminal, accédez au répertoire de votre choix et exécutez les commandes ci-dessous:

 mkdir graphql-intro && cd graphql-intro
npm init -y
npm install graphql-yoga 

Ces instructions ont été utilisées pour créer un dossier pour le projet, initialiser un nouveau projet Node.js et ajouter la dépendance graphql-yoga au projet. graphql-yoga est une bibliothèque qui vous aide à créer facilement des applications serveur GraphQL en fournissant des valeurs par défaut raisonnables. Elle comprend d'autres bibliothèques GraphQL, telles que subscriptions-transport-ws qui est un serveur WebSocket pour GraphQL. abonnements, apollo-server qui est un framework de serveur Web, et graphql-playground un IDE interactif GraphQL que vous pouvez utiliser pour tester votre serveur.

Avec les dépendances installées, nous allons maintenant définir le schéma GraphQL

. Le schéma GraphQL

Le schéma GraphQL est au centre de chaque serveur GraphQL. Il définit l'API du serveur, permettant aux clients de savoir quelles opérations peuvent être effectuées par le serveur. Le schéma est écrit à l'aide du langage de schéma GraphQL (également appelé langage de définition de schéma, SDL). Grâce à elle, vous pouvez définir des types d'objet et des champs pour représenter les données pouvant être extraites à partir de l'API, ainsi que des types racine définissant le groupe d'opérations autorisé par l'API.

Les types de racine sont le type de requête le type de mutation et le type d'abonnement qui sont les trois types d'opérations que vous pouvez exécuter à partir d'un serveur GraphQL. Le type de requête est obligatoire pour tout schéma GraphQL, les deux autres étant facultatifs. Bien que nous puissions définir des types personnalisés dans le schéma, la spécification GraphQL définit également un ensemble de types scalaires intégrés. Ils sont les suivants: Int Float Boolean String et ID .

Continuez et avancez créer un schéma. Ajouter un nouveau fichier src / index.js avec le contenu suivant:

 const typeDefs = `
  type Book {
    id: Int!
    titre: String!
    pages: Int
    chapitres: Int
  }

  tapez Query {
    livres: [Book!]
    book (id: Int!): Réserver
  }
`; 

Ce que nous avons ci-dessus est le schéma GraphQL. Nous y avons défini un type Book avec quatre champs et un type racine Query avec deux champs. Les deux champs de la racine Type de requête définissent les requêtes / opérations que le serveur peut exécuter. Le champ books renvoie une liste de type Book et le champ book renverra un type Book basé sur id est passé comme argument à la requête du livre .

Chaque champ d'un type GraphQL peut avoir zéro argument ou plus. Un point d'exclamation suit les types scalaires affectés à certains champs. Cela signifie que le champ ou l'argument n'est pas nullable.

Implémentation de Resolvers

Notre API est capable d'exécuter deux opérations de requête: une pour extraire un tableau de livres et une autre pour extraire un livre basé sur son id . . La prochaine étape pour nous consiste à définir le mode de résolution de ces requêtes afin que les champs appropriés soient renvoyés au client.

Pour ce faire, définissez une fonction de résolution pour chaque champ du schéma. Rappelez-vous que j'ai mentionné que GraphQL a un algorithme d'exécution? L'implémentation de cet algorithme d'exécution transforme la requête du client en résultat réel, en parcourant tous les champs du schéma et en exécutant leur fonction de «résolveur» pour déterminer le résultat.

Ajoutez le code ci-dessous à . index.js :

 const books = [{
  id: 1,
  title: "Fullstack tutorial for GraphQL",
  pages: 356
}, {
  id: 2,
  title: "Introductory tutorial to GraphQL",
  chapters: 10
}, {
  id: 3,
  title: "GraphQL Schema Design for the Enterprise",
  pages: 550,
  chapters: 25
}];

const résolveurs = {
  Requête: {
    books: fonction (racine, arguments, contexte, informations) {
      retourner des livres;
    },
    book: (racine, arguments, contexte, info) => books.find (e => e.id === args.id)
  },
  Livre: {
    id: parent => parent.id,
    titre: parent => parent.title,
    pages: parent => parent.pages,
    chapitres: parent => parent.chapters
  }
}; 

Dans le code que vous venez d'ajouter, nous avons défini une variable pour conserver nos données en mémoire. Il n'y aura pas d'accès à la base de données dans ce post. La variable resolvers est un objet qui contient des résolvers pour nos types. Les champs dans les propriétés sont nommés d'après les types de notre schéma et sont des objets avec les champs que nous avons définis pour ce type dans le schéma. Les champs définissent chacun leur fonction de résolveur, qui sera exécutée par le moteur GraphQL et devrait résoudre les données réelles de ce champ. Vous remarquerez que les fonctions du type Query ont une déclaration comme celle-ci:

 function (racine, arguments, contexte, info) {// implémentation de la fonction} 

Notez que j'ai utilisé la syntaxe de la fonction de flèche dans ES6 permet de déclarer certaines fonctions de résolveur dans le code

. Ce sont les quatre (4) arguments que chaque fonction de résolveur reçoit. Ils sont décrits comme suit:

  1. root : Cet argument est parfois appelé parent . Il contient le résultat du résolveur précédemment exécuté dans la chaîne d'appels. Par exemple, si nous appelons la requête book son exécution commence à partir du champ racine book dans le type de racine de requête. Après cela, il exécutera les résolveurs du type Book pour obtenir les valeurs de ces champs. Dans le code ci-dessus, j'ai nommé le premier argument des résolveurs des champs de Book comme parent . La valeur de l'argument sera l'objet Book reçu du résolveur parent. C'est pourquoi nous appelons parent.title par exemple, pour renvoyer une valeur pour ce champ.
  2. args : Il s'agit des arguments fournis au champ dans la requête GraphQL. Suivant notre exemple, il s'agira de l'argument id pour le livre query livre (id: Int!): Livre .
  3. contexte : C'est un objet que chaque résolveur peut lire ou écrire. Vous pouvez conserver ici les objets donnant accès à la base de données ou contenant des informations provenant des en-têtes de requête HTTP. Contrairement aux paramètres root et args, leurs valeurs varient en fonction du niveau dans la chaîne d'exécution à partir duquel le résolveur est appelé. L'objet de contexte est le même pour tous les résolveurs et vous pouvez y écrire des informations contextuelles si nécessaire. Nous allons utiliser cet argument dans le prochain post, alors restez branchés!
  4. info : En prenant la définition de ici il contient des informations spécifiques à un champ pertinentes pour la requête en cours ainsi que les détails du schéma . Pour en savoir plus, vous pouvez lire cet excellent post sur le sujet.

Configuration du serveur

Après avoir défini notre schéma et nos résolveurs, nous allons maintenant configurer le serveur GraphQL. Ayant toujours index.js ouvert, mettez-le à jour avec le code suivant:

 const {GraphQLServer} = require ("graphql-yoga");
const typeDefs = ... // définition du schéma de la section précédente
livres const = [
  // array of books object from previous section
];

const résolvers = {...};

const server = new GraphQLServer ({
  typeDefs,
  résolveurs
});

server.start (() => console.log (`le serveur tourne sur http: // localhost: 4000`)]); 

Nous avons importé ici GraphQLServer à partir du graphql-yoga et l'a utilisée pour créer un objet serveur avec notre définition de schéma et nos résolveurs. Avec cela, notre serveur est complet. Il sait quelle opération d'API traiter et comment la traiter. Continuons et testons le serveur.

Langage de requête GraphQL

Ouvrez la ligne de commande et exécutez la commande node src / index.js pour démarrer le serveur. Vous devriez voir Le serveur est exécuté sur http: // localhost: 4000 enregistré dans la console. Ouvrez votre navigateur à cette URL. Il affichera une belle interface. C'est le terrain de jeu GraphQL . Il vous permet de tester les opérations du serveur. Si vous avez créé des API REST, considérez cela comme une alternative Postman à GraphQL.

Demandons maintenant au serveur de nous fournir tous les livres dont il dispose. Comment faisons-nous cela? Pour ce faire, nous utilisons le langage de requête GraphQL, un autre concept de GraphQL facilitant l’interrogation de données à leur guise par différents périphériques, servi à partir de la même API GraphQL.

Allez sur le terrain de jeu GraphQL et exécutez la requête suivante: 19659037] requête {
  livres {
    identifiant
    Titre
    chapitres
  }
}

Vous devriez obtenir le même résultat, comme suit

Vous remarquerez que la requête est structurée de manière similaire au langage de schéma. Le champ books est l'un des champs racine définis dans le type de requête. Ensuite, à l’intérieur des accolades, nous avons le jeu de sélection sur le champ books . Comme ce champ renverra une liste de type Book nous spécifions les champs du type Book que nous voulons récupérer. Nous avons omis le champ pages il n'est donc pas renvoyé par la requête.

Nous pouvons tester la requête book (id) et voir ce qu'elle nous donne.

Dans cette requête, nous plaçons l'argument id sur une valeur de 3 et renvoie exactement ce dont nous avons besoin. Vous remarquerez que j'ai deux questions, livres et livre (id: 3) . Ceci est une requête valide. Le moteur GraphQL sait comment le gérer.

Jusqu'à présent, j'ai abordé quelques notions de base de GraphQL. Nous avons examiné la définition d'un schéma à l'aide du langage de définition de schéma, l'écriture de fonctions de résolution et l'interrogation de l'API GraphQL. J'ai expliqué les quatre paramètres que chaque fonction de résolveur reçoit et nous avons utilisé l'un des paramètres pour résoudre les champs du type Livre. Nous avons créé notre serveur en utilisant graphql-yoga et utilisé GraphQL pour tester notre API. J'ai expliqué que dans GraphQL, nous avons trois types d'opération.

Dans cet article, nous avons travaillé avec l'opération de requête. Dans l'article suivant, nous examinerons les mutations et l'accès à une base de données pour stocker et récupérer des données. Nous mettrons à jour notre schéma afin de pouvoir interroger des données connexes, par exemple des auteurs avec leurs livres ou des livres d'un éditeur particulier. Alors restez à l'écoute!

Voici un lien vers le projet GitHub si vous n'avez pas suivi l'écriture du code vous-même.





Source link