Comment créer une API GraphQl à partir de zéro avec Node JS, Express et MongoDB

Apr 03, 2020☕ ☕ 12 min Follow me on Twitter

Subscribe to receive the free weekly article

Dans ce guide, nous allons construire à partir de zéro une API avec GraphQL, Node JS, Express et MongoDB. Commençons donc par répondre à une question importante: qu'est-ce que GraphQL?

Qu'est-ce que GraphQL?

GraphQL est un langage de requête créé par Facebook. C'est une alternative à l'approche REST. Donc, si vous venez du monde REST, gardez à l'esprit que GraphQL fonctionne différemment. Il a un point de terminaison unique pour toutes sortes de requêtes, et la méthode doit être une requête post. GraphQL fonctionne avec les types et les champs, et il est vraiment puissant car il fournit toutes ou seulement les données nécessaires.

Envoyez une requête GraphQL à votre API et obtenez exactement ce dont vous avez besoin, rien de plus et rien de moins.

Nous verrons GraphQL en action plus tard, mais pour l'instant, planifions notre API.

Configuration de l'API GraphQL

Pour l'API, nous aurons la possibilité de créer des articles et de les stocker avec MongoDB, et aussi de pouvoir les récupérer.

Pour ce faire, nous devons créer un nouveau projet en exécutant la commande suivante dans le terminal.

    yarn init

Dans ce tutoriel, j'utiliserai yarn, vous pouvez utiliser npm si vous le souhaitez aussi. C'est vraiment comme vous voulez.

Ensuite, structurez votre projet comme suit:

├── node_modules
├── graphql
|  ├── resolvers
|  |  └── index.js
|  └── schema
|     └── index.js
├── models
|  └── article.js
├── app.js
├── nodemon.json
├── package.json
└── yarn.lock

Et, comme vous pouvez le voir, nous avons un dossier graphql qui contient le schéma et les résolveurs de l'API.

Ensuite, nous avons un dossier models qui contient ce à quoi devrait ressembler un article et enfin le dernier mais pas des moindres, un fichier nodemon.json pour contenir nos variables d'environnement et le point d'entrée du serveur app.js.

Nous avons quelques bibliothèques à installer, donc je vais garder les choses simples et installer celle dont nous avons besoin au fur et à mesure que nous progressons.

Maintenant, exécutons les commandes suivantes sur le terminal pour installer express et nodemon.

    yarn add express

Ensuite, ajoutez nodemon comme dépendance de développement.

    yarn add nodemon -D

Avec cela, nous pouvons maintenant ajouter un script de démarrage sur le fichier package.json pour pouvoir, comme vous pouvez le deviner, démarrer le serveur.

  • package.json
{
  "name": "graphql-api",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "start": "nodemon app.js"
  },
  "dependencies": {
    "express": "^4.17.1",
  },
  "devDependencies": {
    "nodemon": "^2.0.2"
  }
}

Comme vous pouvez le voir, nous utilisons ici nodemon pour démarrer le serveur et lorsqu'un fichier est ajouté ou mis à jour, nodemon réagira automatiquement à la mise à jour.

Nous avons maintenant la commande pour démarrer le serveur, mais toujours pas de serveur à démarrer. Nous allons créer le serveur plus tard, mais pour l'instant, définissons le schéma de l'API.

Schéma GraphQL

Un schéma décrit la forme de votre graphe de données. Il définit un ensemble de types avec des champs qui sont remplis à partir de vos bases de données principaux.

Et pour créer un schéma, nous devons installer le paquet graphql en exécutant sur le terminal:

    yarn add graphql

Ensuite, nous devons ajouter le bloc de code suivant pour créer un schéma GraphQL.

  • graphql/schema/index.js
const { buildSchema } = require("graphql")

module.exports = buildSchema(`

  type Article {
    _id: ID!
    title: String!
    body: String!
    createdAt: String!
  }


  input ArticleInput {
    title: String!
    body: String!
  }

  type Query {
    articles:[Article!]
  }

  type Mutation {
    createArticle(article:ArticleInput): Article
  }

  schema {
    query: Query
    mutation: Mutation
  }
`)

Pour créer un schéma, nous devons d'abord importer buildSchema à partir de graphql, puis créer nos types. GraphQL fonctionne avec les types, il prend en charge plusieurs types scalaires.

Ici, nous avons le type Article qui doit avoir un _id (vous devez le nommer comme ceci en raison de MongoDB) de type ID, un titre, un corps et un champ createdAt de type String.

Le point d'exclamation ! signifie simplement que le type défini est obligatoire, il doit correspondre au type.

Ensuite, nous avons un type input qui définit à quoi devrait ressembler l'entrée attendue. Ce sont les données saisies par l'utilisateur et seront utilisées pour créer un nouvel article.

Une requête GraphQL comme son nom l'indique est utilisée pour définir un type de requête. Et ici, nous avons une requête articles pour récupérer les données. Il doit renvoyer un tableau, et chaque article doit correspondre au type Article.

Maintenant, pour pouvoir récupérer des articles, nous devons d'abord les créer. Et pour ce faire, nous utilisons une mutation GraphQl. Il s'agit d'une requête qui crée, met à jour ou supprime des données dans la base de données et renvoie une valeur.

Ici, pour créer un nouvel article, nous utilisons la mutation createArticle. Il reçoit un objet de type ArticleInput et renvoie l'article créé.

Nous avons maintenant tout ce dont nous avons besoin pour créer un schéma, la dernière chose à faire est de passer la Query et la Mutation au schéma.

Et voilà, nous avons maintenant un schéma.

Cependant, un schéma GraphQl ne suffit pas, nous devons créer un autre schéma, un modèle pour être précis afin de garantir que les données envoyées à MongoDB correspondent au schéma défini avec GraphQL.

Création de modèles Mongoose

Comme je l'ai mentionné précédemment, MongoDB sera utilisé comme base de données, et pour faciliter les choses, nous utiliserons mongoose pour interagir avec.

Et pour l'installer, nous devons exécuter la commande suivante dans le terminal.

  yarn add mongoose

Ensuite, nous pouvons maintenant créer un modèle pour un article.

  • models/article.js
const mongoose = require("mongoose")

const Schema = mongoose.Schema

const artcleSchema = new Schema(
  {
    title: {
      type: String,
      required: true,
    },

    body: {
      type: String,
      required: true,
    },
  },
  { timestamps: true }
)

module.exports = mongoose.model("Article", artcleSchema)

Pour créer un modèle de données, nous devons d'abord importer mongoose et accéder à la méthode Schema. Avec cela, nous pouvons maintenant créer un schéma pour un article donné. Et si vous vous en souvenez, dans notre schéma GraphQL, nous avons certains champs obligatoires (!), donc ici, nous utilisons la propriété required pour suivre le schéma défini avec GraphQL.

Et pour le _id, nous n'avons pas besoin de l'ajouter en tant que champ dans le schéma car il sera créé automatiquement. C'est la même chose pour createdAt, le deuxième argument timestamps:true indique à mongoose d'ajouter des champs createdAt et updatedAt au schéma.

Maintenant, pour créer le modèle, nous devons utiliser à nouveau mongoose et passer en arguments le nom du modèle et le schéma à la méthode model().

Il semble que nous ayons tout ce dont nous avons besoin pour créer des résolveurs GraphQL pour l'API. Alors, faisons cela dans la section suivante.

Résolveur GraphQl

Un résolveur est une collection de fonctions qui permet de générer une réponse à partir d'une requête GraphQL. Il gère la demande et renvoie une réponse. Et chaque nom de requête ou de mutation doit correspondre exactement au nom de la fonction résolveur. Cela signifie que si nous avons une requête nommée articles, nous devrions avoir une fonction de résolveur articles().

Maintenant, pour créer des résolveurs, nous devons ajouter ce bloc de code ci-dessous dans le fichier graphql/resolvers/index.js.

  • graphql/resolvers/index.js
const Article = require("../../models/article")

module.exports = {
  articles: async () => {
    try {
      const articlesFetched = await Article.find()
      return articlesFetched.map(article => {
        return {
          ...article._doc,
          _id: article.id,
          createdAt: new Date(article._doc.createdAt).toISOString(),
        }
      })
    } catch (error) {
      throw error
    }
  },

  createArticle: async args => {
    try {
      const { title, body } = args.article
      const article = new Article({
        title,
        body,
      })
      const newArticle = await article.save()
      return { ...newArticle._doc, _id: newArticle.id }
    } catch (error) {
      throw error
    }
  },
}

Dans le schéma GraphQL, nous avons une requête nommée articles qui renvoie un tableau d'articles. Par conséquent, nous devrions avoir ici un résolveur du même nom.

La fonction articles utilise le modèle créé avec mongoose pour envoyer la demande à MongoDB. Cela dit, nous pouvons maintenant accéder à .find() et comme le nom suggère, il permet récupérer tous les articles de la base de données.

La valeur retournée est un tableau, par conséquent, nous devons le parcourir et pour chaque objet retourner le document (c'est un objet qui contient les données), remplacer le _id par mongoose et convertir le champ createdAt en une date plus conviviale.

Et, comme vous le savez déjà, cette opération peut prendre du temps, c'est la raison pour laquelle nous utilisons async/wait pour traiter la demande.

Pour la deuxième fonction résolveur createArticle, elle gère la mutation définie précédemment dans le schéma GraphQL. Il reçoit en argument l'objet article, et avec cela, il crée un nouvel article basé sur le modèle Article.

Et pour le stocker dans MongoDB, il suffit d'utiliser un autre assistant fourni par mongoose, la méthode save() et de renvoyer comme prévu dans le schéma GraphQL l'article nouvellement créé.

Au passage, la réponse envoyée par MongoDB contient des métadonnées, c'est pourquoi pour les deux fonctions, je renvoie directement la propriété _doc.

Avec ce changement, nous avons maintenant un schéma et des résolveurs pour notre API GraphQL, c'est à peu près ce dont nous avons besoin pour passer à la section suivante et créer un serveur et un point de terminaison.

Créez le serveur et un point de terminaison

Dans le fichier package.json, nous avons un script pour démarrer le serveur. Et cela commence par le fichier app.js, nous devons donc mettre à jour ce fichier pour avoir un vrai serveur.

Avant d'écrire la logique de création d'un serveur, nous devons installer express-graphql qui est la colle entre graphql et express.

Et pour l'installer, nous devons exécuter la commande suivante sur le terminal.

const express = require("express")
const graphqlHttp = require("express-graphql")
const graphqlSchema = require("./graphql/schema")
const graphqlResolvers = require("./graphql/resolvers")

const app = express()

app.use(
  "/graphql",
  graphqlHttp({
    schema: graphqlSchema,
    rootValue: graphqlResolvers,
    graphiql: true,
  })
)

app.listen(3000, () => console.log("Server is running on localhost:3000"))

Comme vous pouvez le voir, nous importons ici le schéma et les résolveurs créés précédemment. Et pour les utiliser, nous avons besoin de graphqlHttp (vous pouvez le nommer comme vous voulez). C'est une méthode fournie par express-graphql qui attend certaines options. Ici, il reçoit le schéma et le résolveur, j'ai également activé graphiql qui est un outil sympa pour tester les requêtes.

Le point de terminaison pour toutes les demandes sera /graphql, et pour pouvoir atteindre ce point de terminaison, nous devons démarrer le serveur et écouter le port 3000.

Génial! nous avons maintenant une API fonctionnelle, mais jusqu'à présent, il manque quelque chose: l'API n'est pas encore connectée à MongoDB. Corrigeons cela dans la section suivante.

Connexion l'API à MongoDB

Si vous vous souvenez, dans le dossier de structure, nous avions un fichier nodemon.json, ce fichier sera utilisé maintenant pour stocker nos variables d'environnement.

Mais d'abord, vous devrez créer un nouveau cluster sur MongoDB Atlas et obtenir le nom d'utilisateur et le mot de passe de la base de données.

Ensuite, mettez à jour les informations d'identification avec les vôtres.

  • nodemon.json.
{
    "env": {
        "MONGO_USER": "your_username",
        "MONGO_PASSWORD": "your_password",
        "MONGO_DB": "your_database"
    }
}

Maintenant que nous avons les informations d'identification nécessaires, il est temps de connecter l'API à MongoDB. Et pour ce faire, nous devons modifier un peu app.js.

const express = require("express")
const graphqlHttp = require("express-graphql")
const mongoose = require("mongoose")
const graphqlSchema = require("./graphql/schema")
const graphqlResolvers = require("./graphql/resolvers")

const app = express()

app.use(
  "/graphql",
  graphqlHttp({
    schema: graphqlSchema,
    rootValue: graphqlResolvers,
    graphiql: true,
  }))const uri = `mongodb+srv://${process.env.MONGO_USER}:${process.env.MONGO_PASSWORD}@cluster0-uox7n.mongodb.net/${process.env.MONGO_DB}?retryWrites=true&w=majority`const options = { useNewUrlParser: true, useUnifiedTopology: true }mongoose  .connect(uri, options)
  .then(() => app.listen(3000, console.log("Server is running")))
  .catch(error => {
    throw error
  })

Ce lien provient de MongoDB Atlas, il nous permet de nous connecter à la base de données. Et j'utilise également les informations d'identification détenues sur nodemon.json pour construire le uri.

Ensuite, nous utilisons à nouveau mongoose et passons en paramètre le uri et quelques options à la méthode connect(). Et lorsque l'opération est terminée avec succès, nous démarrons le serveur, sinon, une erreur sera envoyée.

Avec ce changement, nous avons maintenant connecté l'API à MongoDB. Il est maintenant temps de le tester avec le playground GraphQL pour voir si l'API fonctionne comme prévu.

Testez l'API avec GraphiQL

Pour accéder au playground GraphQL, nous devons démarrer le serveur avec la commande suivante:

  yarn start

Maintenant, si vous accédez à http://localhost:3000/graphql, vous pourrez jouer avec GraphiQL.

  • Créer un nouvel article

Pour créer un article, nous devons envoyer une requête de mutation.

mutation

Il semble que cela fonctionne parfaitement, la mutation crée un nouvel article et le renvoie comme prévu.

Maintenant, essayons de récupérer les articles stockés sur MongoDB.

  • Récupérer les articles

Comme je l'ai dit plus tôt, GraphQL nous permet de récupérer tous ou seulement les champs dont nous avons besoin.

requête

Et ici, je veux récupérer pour chaque article le titre, le corps et, createdAt de la base de données. Et, comme vous pouvez le voir, la réponse renvoyée par MongoDB est celle attendue.

Génial! Nous avons maintenant terminé la construction d'une API GraphQL à partir de zéro avec Node JS, Express et MongoDB.

Vous pouvez trouver le code source ici

Merci d'avoir lu

#node#graphql#express

Support my work

Get articles in your inbox