Construire des API GraphQL avec Node
Publié: 2022-12-20GraphQL est le nouveau mot à la mode dans le développement d'API. Bien que les API RESTful restent le moyen le plus populaire d'exposer les données des applications, elles s'accompagnent de nombreuses limitations que GraphQL vise à résoudre.
GraphQL est un langage de requête créé par Facebook, qui a été transformé en projet open source en 2015. Il offre une syntaxe intuitive et flexible pour décrire et accéder aux données dans une API.
Ce guide explorera comment créer un projet GraphQL Node.js. Nous utiliserons GraphQL pour créer une application Todo dans le framework Web Express.js pour Node.
Qu'est-ce que GraphQL ?
De la documentation officielle : « GraphQL est un langage de requête pour les API et un runtime pour répondre à ces requêtes avec vos données existantes. GraphQL fournit une description complète et compréhensible des données de votre API, donne aux clients le pouvoir de demander exactement ce dont ils ont besoin et rien de plus, facilite l'évolution des API au fil du temps et active de puissants outils de développement.
GraphQL est un environnement d'exécution côté serveur permettant d'exécuter des requêtes à l'aide du système de type que vous avez défini pour vos données. De plus, GraphQL n'est lié à aucune base de données ou moteur de stockage spécifique. Au lieu de cela, il est soutenu par votre code existant et votre magasin de données. Vous pouvez obtenir une comparaison détaillée de ces technologies avec le guide API GraphQL vs RESTful.
Pour créer un service GraphQL, commencez par définir des types de schéma et créez des champs à l'aide de ces types. Ensuite, vous fournissez un résolveur de fonction à exécuter sur chaque champ et tapez chaque fois que des données sont demandées par le côté client.
Terminologie GraphQL
Le système de type GraphQL est utilisé pour décrire quelles données peuvent être interrogées et quelles données vous pouvez manipuler. C'est le cœur de GraphQL. Discutons des différentes manières dont nous pouvons décrire et manipuler les données dans GraphQ.
Les types
Les types d'objets GraphQL sont des modèles de données contenant des champs fortement typés. Il devrait y avoir un mappage 1 à 1 entre vos modèles et les types GraphQL. Vous trouverez ci-dessous un exemple de type GraphQL :
type User { id: ID! # The "!" means required firstname: String lastname: String email: String username: String todos: [Todo] # Todo is another GraphQL type }
Requêtes
GraphQL Query définit toutes les requêtes qu'un client peut exécuter sur l'API GraphQL. Vous devez définir une RootQuery qui contiendra toutes les requêtes existantes par convention.
Ci-dessous, nous définissons et mappons les requêtes à l'API RESTful correspondante :
type RootQuery { user(id: ID): User # Corresponds to GET /api/users/:id users: [User] # Corresponds to GET /api/users todo(id: ID!): Todo # Corresponds to GET /api/todos/:id todos: [Todo] # Corresponds to GET /api/todos }
mutation
Si les requêtes GraphQL sont des requêtes GET , les mutations sont les requêtes POST , PUT , PATCH et DELETE qui manipulent l'API GraphQL.
Nous allons mettre toutes les mutations dans une seule RootMutation pour démontrer :
type RootMutation { createUser(input: UserInput!): User # Corresponds to POST /api/users updateUser(id: ID!, input: UserInput!): User # Corresponds to PATCH /api/users removeUser(id: ID!): User # Corresponds to DELETE /api/users createTodo(input: TodoInput!): Todo updateTodo(id: ID!, input: TodoInput!): Todo removeTodo(id: ID!): Todo }
Vous avez remarqué l'utilisation de types -input pour les mutations telles que UserInput , TodoInput . Il est toujours recommandé de toujours définir des types d'entrée pour créer et mettre à jour vos ressources.
Vous pouvez définir les types d'entrée comme celui ci-dessous :
input UserInput { firstname: String! lastname: String email: String! username: String! }
Résolveurs
Les résolveurs indiquent à GraphQL quoi faire lorsque chaque requête ou mutation est demandée. Il s'agit d'une fonction de base qui effectue le travail acharné consistant à atteindre la couche de base de données pour effectuer les opérations CRUD (créer, lire, mettre à jour, supprimer), à atteindre un point de terminaison API RESTful interne ou à appeler un microservice pour répondre à la demande du client.
Vous pouvez créer un nouveau fichier resolvers.js et ajouter le code suivant :
import sequelize from '../models'; export default function resolvers () { const models = sequelize.models; return { // Resolvers for Queries RootQuery: { user (root, { id }, context) { return models.User.findById(id, context); }, users (root, args, context) { return models.User.findAll({}, context); } }, User: { todos (user) { return user.getTodos(); } }, } // Resolvers for Mutations RootMutation: { createUser (root, { input }, context) { return models.User.create(input, context); }, updateUser (root, { id, input }, context) { return models.User.update(input, { ...context, where: { id } }); }, removeUser (root, { id }, context) { return models.User.destroy(input, { ...context, where: { id } }); }, // ... Resolvers for Todos go here } }; }
Schéma
Le schéma GraphQL est ce que GraphQL expose au monde. Par conséquent, les types, les requêtes et les mutations seront inclus dans le schéma pour être exposés au monde.
Vous trouverez ci-dessous comment exposer les types, les requêtes et les mutations au monde :
schema { query: RootQuery mutation: RootMutation }
Dans le script ci-dessus, nous avons inclus les RootQuery et RootMutation que nous avons créés précédemment pour être exposés au monde.
Comment fonctionne GraphQL avec Nodejs et Expressjs
GraphQL fournit une implémentation pour tous les principaux langages de programmation, et Node.js n'est pas exempté. Sur le site Web officiel de GraphQL, il existe une section pour la prise en charge de JavaScript, ainsi que d'autres implémentations de GraphQL pour simplifier l'écriture et le codage dans GraphQL.
GraphQL Apollo fournit une implémentation pour Node.js et Express.js et facilite la prise en main de GraphQL.
Vous apprendrez à créer et à développer votre première application GraphQL dans le framework backend Nodes.js et Express.js à l'aide de GraphQL Apollo dans la section suivante.
Configuration de GraphQL avec Express.js
La création d'un serveur d'API GraphQL avec Express.js est simple à démarrer. Dans cette section, nous allons explorer comment construire un serveur GraphQL.
Initialiser le projet avec Express
Tout d'abord, vous devez installer et configurer un nouveau projet Express.js.
Créez un dossier pour votre projet et installez Express.js à l'aide de cette commande :
cd <project-name> && npm init -y npm install express
La commande ci-dessus crée un nouveau fichier package.json et installe la bibliothèque Express.js dans votre projet.
Ensuite, nous allons structurer notre projet comme indiqué dans l'image ci-dessous. Il contiendra différents modules pour les fonctionnalités du projet telles que les utilisateurs, les tâches, etc.
Initialiser GraphQL
Commençons par installer les dépendances GraphQL Express.js. Exécutez la commande suivante pour installer :
npm install apollo-server-express graphql @graphql-tools/schema --save
Création de schémas et de types
Ensuite, nous allons créer un fichier index.js dans le dossier modules et ajouter l'extrait de code suivant :
const { gql } = require('apollo-server-express'); const users = require('./users'); const todos = require('./todos'); const { GraphQLScalarType } = require('graphql'); const { makeExecutableSchema } = require('@graphql-tools/schema'); const typeDefs = gql` scalar Time type Query { getVersion: String! } type Mutation { version: String! } `; const timeScalar = new GraphQLScalarType({ name: 'Time', description: 'Time custom scalar type', serialize: (value) => value, }); const resolvers = { Time: timeScalar, Query: { getVersion: () => `v1`, }, }; const schema = makeExecutableSchema({ typeDefs: [typeDefs, users.typeDefs, todos.typeDefs], resolvers: [resolvers, users.resolvers, todos.resolvers], }); module.exports = schema;
Procédure pas à pas
Passons en revue l'extrait de code et décomposons-le :
Étape 1
Tout d'abord, nous avons importé les bibliothèques requises et créé des types de requête et de mutation par défaut. La requête et la mutation définissent uniquement la version de l'API GraphQL pour le moment. Cependant, nous étendrons la requête et la mutation pour inclure d'autres schémas au fur et à mesure.
Étape 2:
Ensuite, nous avons créé un nouveau type scalaire pour le temps et notre premier résolveur pour la requête et la mutation créées ci-dessus. De plus, nous avons également généré un schéma à l'aide de la fonction makeExecutableEchema .
Le schéma généré inclut tous les autres schémas que nous avons importés et en inclura également d'autres lorsque nous les créerons et les importerons.
L'extrait de code ci-dessus montre que nous avons importé différents schémas dans la fonction makeExecutableEchema. Cette approche nous aide à structurer l'application pour la complexité. Ensuite, nous allons créer les schémas Todo et User que nous avons importés.
Création du schéma Todo
Le schéma Todo montre des opérations CRUD simples que les utilisateurs de l'application peuvent effectuer. Vous trouverez ci-dessous le schéma qui implémente l'opération Todo CRUD.
const { gql } = require('apollo-server-express'); const createTodo = require('./mutations/create-todo'); const updateTodo = require('./mutations/update-todo'); const removeTodo = require('./mutations/delete-todo'); const todo = require('./queries/todo'); const todos = require('./queries/todos'); const typeDefs = gql` type Todo { id: ID! title: String description: String user: User } input CreateTodoInput { title: String! description: String isCompleted: Boolean } input UpdateTodoInput { title: String description: String isCompleted: Boolean } extend type Query { todo(id: ID): Todo! todos: [Todo!] } extend type Mutation { createTodo(input: CreateTodoInput!): Todo updateTodo(id: ID!, input: UpdateTodoInput!): Todo removeTodo(id: ID!): Todo } `; // Provide resolver functions for your schema fields const resolvers = { // Resolvers for Queries Query: { todo, todos, }, // Resolvers for Mutations Mutation: { createTodo, updateTodo, removeTodo, }, }; module.exports = { typeDefs, resolvers };
Procédure pas à pas
Passons en revue l'extrait de code et décomposons-le :
Étape 1:
Tout d'abord, nous avons créé un schéma pour notre Todo en utilisant GraphQL type , input et extend . Le mot clé extend est utilisé pour hériter et ajouter de nouvelles requêtes et mutations à la requête racine existante et à la mutation que nous avons créées ci-dessus.
Étape 2:
Ensuite, nous avons créé un résolveur, qui est utilisé pour récupérer les données correctes lorsqu'une requête ou une mutation particulière est appelée.
Avec la fonction de résolution en place, nous pouvons créer des méthodes individuelles pour la logique métier et la manipulation de la base de données, comme indiqué dans l'exemple create-todo.js .
Créez un fichier create-user.js dans le dossier <code>./mutations</code> et ajoutez la logique métier pour créer une nouvelle Todo dans votre base de données.
const models = require('../../../models'); module.exports = async (root, { input }, context) => { return models.todos.push({ ...input }); };
L'extrait de code ci-dessus est un moyen simplifié de créer un nouveau Todo dans notre base de données à l'aide de l'ORM Sequelize. Vous pouvez en savoir plus sur Sequelize et comment le configurer avec Node.js.
Vous pouvez suivre la même étape pour créer de nombreux schémas en fonction de votre application ou vous pouvez cloner le projet complet à partir de GitHub.
Ensuite, nous allons configurer le serveur avec Express.js et exécuter l'application Todo nouvellement créée avec GraphQL et Node.js
Configuration et exécution du serveur
Enfin, nous allons configurer notre serveur à l'aide de la bibliothèque apollo-server-express que nous avons installée précédemment et la configurer.
apollo-server-express est un simple wrapper d'Apollo Server pour Express.js, il est recommandé car il a été développé pour s'adapter au développement d'Express.js.
En utilisant les exemples dont nous avons discuté ci-dessus, configurons le serveur Express.js pour qu'il fonctionne avec le apollo-server-express nouvellement installé.
Créez un fichier server.js dans le répertoire racine et collez-y le code suivant :
const express = require('express'); const { ApolloServer } = require('apollo-server-express'); const schema = require('./modules'); const app = express(); async function startServer() { const server = new ApolloServer({ schema }); await server.start(); server.applyMiddleware({ app }); } startServer(); app.listen({ port: 3000 }, () => console.log(`Server ready at http://localhost:3000`) );
Dans le code ci-dessus, vous avez créé avec succès votre premier serveur CRUD GraphQL pour Todos et Users. Vous pouvez démarrer votre serveur de développement et accéder au terrain de jeu en utilisant http://localhost:3000/graphql. Si tout est réussi, l'écran ci-dessous devrait s'afficher :
Résumé
GraphQL est une technologie moderne prise en charge par Facebook qui simplifie le travail fastidieux impliqué dans la création d'API à grande échelle avec des modèles architecturaux RESTful.
Ce guide a expliqué GraphQL et montré comment développer votre première API GraphQL avec Express.js.
Faites-nous savoir ce que vous construisez en utilisant GraphQL.