Fermer

août 14, 2019

GraphQL: Mutation et accès à la base de données


GraphQL, décrit comme un langage d'interrogation et de manipulation des données pour les API, et Runtime permettant de traiter des requêtes avec des données existantes, permet à différents clients d’utiliser votre API et d’interroger uniquement les données dont ils ont besoin. Cela aide à résoudre certains problèmes rencontrés par certains services REST, tels que les excès et les excès d'extraction qui constituent un problème de performances.

Dans mon post précédent j'ai écrit sur le système de type GraphQL, le langage de requête, le schéma et le résolveur. Je vous ai montré comment construire un serveur GraphQL avec graphql-yoga et testé l'API avec certaines requêtes du terrain de jeu GraphQL. Dans cet article, je vais vous présenter la mutation GraphQL. Nous allons également quitter le magasin en mémoire utilisé précédemment et utiliser une base de données pour accéder à nos données et les stocker.

Ajout d'une base de données

Si vous n'avez pas suivi le post précédent, vous pouvez télécharger le fichier. code source sur GitHub . Le code complet du post précédent est contenu dans le dossier src-part-1 . Si vous souhaitez suivre le codage, renommez ce dossier en src et suivez les instructions de codage à partir de maintenant.

Avant de passer à la création de mutations GraphQL, je souhaite que nous utilisions une base de données pour le. requêtes existantes que nous avons dans notre système GraphQL. Nous allons utiliser Prisma comme couche d'accès aux données via une base de données MySQL. Pour cet exemple, nous allons utiliser le serveur de démonstration Prisma exécuté sur le service Prisma Cloud.

Continuons et définissons un schéma de base de données. Ajouter un nouveau fichier, src / prisma / datamodel.prisma avec le contenu suivant:

 type Book {
  J'ai fait! @id
  titre: String!
  pages: Int
  chapitres: Int
  auteurs: [Author!]!
}

type Auteur {
  J'ai fait! @id
  nom: String! @unique
  livres: [Book!]!
} 

Le schéma ci-dessus représente notre modèle de données. Chaque type sera mappé à une table de base de données. Avoir ! avec un type rendra cette colonne dans la base de données non nullable. Nous avons également annoté certains champs avec la directive @ et sont utilisées dans le langage de schéma ou le langage de requête. La directive @unique marquera cette colonne avec une contrainte unique dans la base de données. Cela nous permettra également de trouver les auteurs par leur nom, comme vous le verrez plus tard.

Ensuite, nous ajoutons un nouveau fichier src / prisma / prisma.yml qui contiendra des options de configuration pour Prisma: [19659011] # le point de terminaison HTTP du serveur de démonstration sur Prisma Cloud
point final: ""

# pointe vers le fichier contenant votre modèle de données
datamodel: datamodel.prisma

# spécifie la langue et l'emplacement du client Prisma généré
produire:
– générateur: javascript-client
Ce fichier sera utilisé par la CLI Prisma pour configurer et mettre à jour le serveur Prisma dans le cloud et générer une API client basée sur le modèle de données. L'option endpoint contient l'URL du serveur Prisma Cloud. L'option datamodel spécifie un chemin d'accès au modèle de données, l'option generate spécifie que nous utilisons le générateur de client JavaScript et qu'il devrait générer les fichiers client vers le fichier / client dossier.

Prisma CLI peut générer le client à l'aide d'autres générateurs. Il existe actuellement des générateurs pour TypeScript et Go. Nous travaillons avec JavaScript et j'ai donc choisi d'utiliser le générateur javascript-client . Pour en savoir plus sur la structure de ce fichier de configuration, n'hésitez pas à consulter la documentation .

Nous avons besoin de la CLI Prisma pour déployer notre serveur Prisma et générer le client Prisma. Nous installerons l'interface de ligne de commande globalement à l'aide de npm:

 npm install -g prisma 

Au moment de la rédaction de ce document, j'utilise actuellement la version 1.34.0 de la CLI. Avec cela installé, nous devons maintenant déployer notre modèle de données. Suivez les instructions ci-dessous pour configurer la base de données sur le nuage Prisma.

  1. Exécuter cd src / prisma && prisma deploy dans la ligne de commande.
  2. Vous serez invité à choisir le mode de paramétrage souhaité. le serveur Prisma. Sélectionnez Demo Server pour continuer.
  3. Il se peut que la CLI souhaite authentifier votre demande en ouvrant une fenêtre de navigateur vous permettant de vous connecter ou de vous inscrire à Prisma. Une fois que vous êtes connecté, fermez la fenêtre et revenez à l'invite de commande.
  4. L'invite suivante vous demande de choisir une région pour le serveur de démonstration hébergé sur Prisma Cloud. Choisissez celui de votre choix et appuyez sur . Entrez pour continuer.
  5. Vous êtes maintenant invité à choisir un nom pour le service. Entrez graphql-intro (ou un nom de votre choix) et continuez
  6. L'invite suivante demande un nom pour indiquer l'étape actuelle de notre flux de travail. Acceptez la valeur par défaut en appuyant sur . Entrez pour continuer.

La CLI utilise ces informations et celles de prisma.yml pour configurer le serveur de démonstration. Une fois cela fait, il met à jour le fichier avec le noeud final sur le serveur Prisma. Cela affichera également dans la console les informations relatives à la configuration de la base de données.

Une fois le serveur configuré, l'étape suivante consiste à générer le client Prisma pour notre modèle de données. Le client Prisma est généré automatiquement en fonction de votre modèle de données et vous fournit une API pour communiquer avec le service Prisma. Exécutez la commande suivante pour générer notre client Prisma:

 prisma generate 

Cette commande génère l'API du client pour accéder au serveur de démonstration créé précédemment. Il devrait vider quelques fichiers dans src / prisma / client . La prochaine étape pour nous consiste à connecter notre serveur GraphQL au serveur de base de données à l'aide du client Prisma et à en extraire les données.

Ouvrez src / index.js et importez l'instance Prisma exportée à partir du client généré. , puis supprimez la variable books .

 const {GraphQLServer} = require ('graphql-yoga');
const {prisma} = require ('./ prisma / client')

// ... le reste du code reste inchangé 

Nous avons également besoin d'une dépendance nécessaire à l'exécution du client Prisma. Ouvrez la ligne de commande et exécutez la commande npm install prisma-client-lib pour installer ce paquet.

Utilisation de Prisma Client dans Resolvers

Nous avons maintenant un client Prisma généré, nous avons besoin de d'utiliser cela dans nos résolveurs. Nous allons transmettre l'instance Prisma en utilisant l'argument de contexte obtenu par chaque fonction de résolution. Nous avons parlé brièvement de cet argument dans le dernier post, et maintenant vous allez l'utiliser. J'ai mentionné que l'argument context est utile pour conserver des informations contextuelles et que vous pouvez lire ou écrire des données dessus. Pour travailler avec le client Prisma, nous écrirons l'instance Prisma du client généré à l'objet de contexte une fois le client GraphQL initialisé.

Dans src / index.js ligne 32, mettez à jour l'initialisation du GraphQLServer comme suit:

 const server = new GraphQLServer ({
  typeDefs,
  résolveurs,
  contexte: {prisma}

Nous mettrons également à jour les résolveurs afin qu’ils utilisent Prisma pour résoudre les requêtes. Mettez à jour la propriété Query dans la variable de résolution comme suit:

 const resolvers = {
  Requête: {
    books: (root, arguments, context, info) => context.prisma.books (),
    book: (root, args, context, info) => context.prisma.book ({id: args.id})
  },
  // ...
} 

Dans ces résolveurs, nous appelons une fonction sur l'instance du client Prisma attachée au contexte. La fonction prisma.books () nous donne tous les livres de la base de données, alors que prisma.book ({id: args.id}) nous fournit un livre basé sur le passé dans id .

Ajout des opérations de mutation

Jusqu'à présent, nous sommes en mesure d'extraire des données de l'API GraphQL, mais nous avons besoin d'un moyen de les mettre à jour sur le serveur. La mutation GraphQL est un type d'opération qui permet aux clients de modifier des données sur le serveur. C'est grâce à ce type d'opération que nous pouvons ajouter, supprimer et mettre à jour des enregistrements sur le serveur. Pour lire les données, nous utilisons le type d'opération de requête GraphQL, que vous avez appris dans l'article précédent, et que nous avons abordé dans la section précédente.

Nous allons ajouter une nouvelle fonctionnalité à notre API GraphQL afin d'ajouter des livres et des auteurs. . Nous allons commencer par mettre à jour le schéma GraphQL. Mettez à jour la variable typeDefs dans index.js comme suit:

 const typeDefs = `
  type Book {
    J'ai fait!
    titre: String!
    pages: Int
    chapitres: Int
    auteurs: [Author!]!
  }

  type Auteur {
    J'ai fait!
    nom: String!
    livres: [Book!]!
  }

  tapez Query {
    livres: [Book!]
    book (id: ID!): Livre
    auteurs: [Author!]
  }

  type Mutation {
    livre (titre: String !, auteurs: [String!] !, pages: Int, chapitres: Int): Book!
  }
`; 

Nous avons mis à jour notre schéma GraphQL pour ajouter de nouveaux types, Author et Mutation . Nous avons ajouté un nouveau champ authors qui est une liste de Author pour le type de livre et un nouveau champ author: [Author!] pour le type de requête racine. J'ai également modifié les champs nommés id pour utiliser le type ID . En effet, nous utilisons ce type dans notre modèle de données et la base de données générera un identificateur unique global pour ces champs, qui ne correspondra pas au type Int que nous avons utilisé jusqu'à présent. Le type racine Mutation définit notre opération de mutation et ne contient qu'un seul champ appelé livre qui prend en compte les paramètres nécessaires à la création d'un livre.

La prochaine étape de notre processus d'ajouter une mutation à l'API consiste à implémenter des résolveurs pour les nouveaux champs et types que nous avons ajoutés. Avec index.js toujours ouvert, passez à la ligne 30 où la variable résolvers est définie et ajoutez un nouveau champ Mutation à l'objet comme suit:

 const resolvers = {
  Mutation: {
    book: async (racine, arguments, contexte, info) => {
      let authorsToCreate = [];
      let authorsToConnect = [];
      for (const authorName of args.authors) {
        const author = wait context.prisma.author ({name: authorName});
        if (author) authorsToConnect.push (author);
          else authorsToCreate.push ({name: authorName});
        }
        retourne context.prisma.createBook ({
          titre: args.title,
          pages: args.pages,
          chapitres: args.chapters,
          auteurs: {
            créer: authorsToCreate,
            connect: authorsToConnect
          }
      });
    }
  },
  Requête: {
    // ...
  },
  Livre: {
    // ...
  }

Comme toutes les fonctions de résolution, le résolveur de livres dans le type de mutation racine prend quatre arguments et nous obtenons les données à créer à partir du paramètre args et de l'instance Prisma. du paramètre context. Ce résolveur est implémenté de telle sorte qu'il créera l'enregistrement de livre dans la base de données, créera l'auteur s'il n'existe pas, puis liera les deux enregistrements en fonction de la relation de données définie dans notre modèle de données. Tout cela sera fait en une seule transaction dans la base de données. Nous avons utilisé ce que Prisma appelle un objet imbriqué écrit pour modifier plusieurs enregistrements de base de données sur plusieurs relations dans une même transaction.

Bien que nous ayons le résolveur pour le type de mutation racine, nous devons encore ajouter des résolveurs pour le type. new Author et les nouveaux champs ajoutés aux types Query et Book . Mettez à jour les résolveurs Book et Query comme suit:

 const resolvers = {
  Mutation: {
    // ...
  },
  Requête: {
    books: (root, arguments, context, info) => context.prisma.books (),
    book: (root, args, context, info) => context.prisma.book ({id: args.id}),
    auteurs: (racine, arguments, contexte, info) => context.prisma.authors ()
  },
  Livre: {
    authors: (parent, args, context) => context.prisma.book ({id: parent.id}). authors ()
  },
  Auteur: {
    books: (parent, args, context) => context.prisma.author ({id: parent.id}). books ()
  }

Le résolveur de champs authors de l'opération de requête racine est aussi simple que d'appeler prisma.authors () pour obtenir tous les auteurs de la base de données. Vous devriez remarquer les résolveurs pour les champs de types scalaires dans Book et Author a été omis. En effet, le serveur GraphQL peut déduire comment résoudre ces champs en faisant correspondre le résultat à une propriété du même nom issue du paramètre parent . Les autres champs de relation que nous avons ne peuvent pas être résolus de la même manière, nous avons donc dû fournir une implémentation. Nous appelons Prisma pour obtenir ces données, comme vous l'avez vu.

Après toutes ces modifications, votre index.js devrait être identique à celui ci-dessous:

 const {GraphQLServer} = require ('graphql-yoga');
const {prisma} = require ('./ prisma / client');

const typeDefs = `
  type Book {
    J'ai fait!
    titre: String!
    pages: Int
    chapitres: Int
    auteurs: [Author!]!
  }

  type Auteur {
    J'ai fait!
    nom: String!
    livres: [Book!]!
  }

  tapez Query {
    livres: [Book!]
    book (id: ID!): Livre
    auteurs: [Author!]
  }

  type Mutation {
    livre (titre: String !, auteurs: [String!] !, pages: Int, chapitres: Int): Book!
  }
`;

const résolveurs = {
  Mutation: {
    book: async (racine, arguments, contexte, info) => {
      let authorsToCreate = [];
      let authorsToConnect = [];

      for (const authorName of args.authors) {
        const author = wait context.prisma.author ({name: authorName});
        if (author) authorsToConnect.push (author);
        else authorsToCreate.push ({name: authorName});
      }

      retourne context.prisma.createBook ({
        titre: args.title,
        pages: args.pages,
        chapitres: args.chapters,
        auteurs: {
          créer: authorsToCreate,
          connect: authorsToConnect
        }
      });
    }
  },
  Requête: {
    books: (root, arguments, context, info) => context.prisma.books (),
    book: (root, args, context, info) => context.prisma.book ({id: args.id}),
    auteurs: (racine, arguments, contexte, info) => context.prisma.authors ()
  },
  Livre: {
    authors: (parent, args, context) => context.prisma.book ({id: parent.id}). authors ()
  },
  Auteur: {
    books: (parent, args, context) =>
    context.prisma.author ({id: parent.id}). books ()
  }
};

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

server.start (() => console.log (`le serveur est exécuté sur http: // localhost: 4000`))); 

Test de l'API GraphQL

Jusqu'à présent, nous avons mis à jour notre schéma et ajouté des résolveurs à appelez le serveur de base de données pour obtenir des données. Nous sommes maintenant arrivés au point où nous devons tester notre API et voir si elle fonctionne comme prévu. Ouvrez la ligne de commande et exécutez le noeud src / index.js pour démarrer le serveur. Ouvrez ensuite localhost: 4000 dans votre navigateur. Cela devrait faire apparaître le terrain de jeu GraphQL. Copiez et exécutez la requête ci-dessous pour ajouter un livre:

 mutation {
  livre (titre: "Introduction to GraphQL", pages: 150, chapitres: 12, auteurs: ["Peter Mbanugo", "Peter Smith"]) {
    Titre
    des pages
    auteurs {
      prénom
    }
  }
} 

Maintenant que le livre est créé, nous pouvons interroger et voir comment pour les auteurs de l'application:

 query {
  auteurs {
    prénom
    livres {
      Titre
    }
  }
} 

Je vous ai présenté la mutation GraphQL, l'un des trois types d'opération racine de GraphQL. Nous avons mis à jour notre schéma avec de nouvelles fonctionnalités, notamment une mutation pour ajouter des livres à l'application et l'utilisation de Prisma comme couche d'accès à la base de données. Je vous ai montré comment travailler avec un modèle de données en utilisant le même langage de définition de schéma de GraphQL, en travaillant avec la CLI et générer un client Prisma et comment lire en . ] et écrivent des données à l'aide du client Prisma. Comme nos données sont stockées sur Prisma Cloud, vous pouvez accéder à vos services et à votre base de données en ligne à l'adresse app.prisma.io .

Vous avez ajouté de nouvelles fonctionnalités à notre application dans cet article. Cela devrait vous laisser les compétences nécessaires pour créer une API GraphQL permettant d'effectuer des opérations CRUD. Cela devrait vous permettre de vanter avec vos amis que vous êtes maintenant un développeur GraphQL. Pour vous le prouver, je souhaite que vous ajoutiez un nouvel ensemble de fonctionnalités à votre API, comme suit:

  1. Ajoutez une requête pour rechercher les auteurs par leur nom
  2. Autoriser les livres à avoir des éditeurs. Cela vous permettra d'ajouter un nouveau type au schéma. Vous devriez pouvoir ajouter indépendamment des éditeurs et interroger tous les livres appartenant à un éditeur.

Bien que cette compétence fasse de vous un fier développeur de GraphQL, je ne m'arrête pas là. Je veux surcharger vos compétences pour vous rendre plus professionnel. Dans le prochain article, je vais vous enseigner l'authentification sur un serveur GraphQL et un abonnement GraphQL. Alors restez à l’écoute et gardez l’esprit de codage! ??‍???❤️

Vous pouvez trouver le code complet de ce message sur GitHub . Téléchargez le code source et accédez au dossier src-part-2 .





Source link