Apprenez à configurer et à définir un serveur GraphQL pour permettre aux clients de demander les données exactes qu’ils souhaitent dans une application Angular.
Lorsque nous créons des applications Angular, la plupart du temps, les données de nos applications sont transférées à l’aide des API REST depuis le serveur. Par exemple, lorsque le projet précédent Magasin de kendo affiche une liste de produits, Angular demande le point de terminaison fakestore.com/products et le serveur renvoie tous les produits.
Cela semble normal, mais une application Angular ne fait que partie de l’activité ou du flux de travail d’une entreprise ou d’un produit. Ainsi, le produit de l’entité peut avoir plusieurs cas d’utilisation, comme afficher une liste de produits, répertorier uniquement l’image et le titre pour les sections d’offres, ou sur mobile afficher uniquement le titre et le prix et ignorer les informations restantes.
Le développeur backend définit les modèles avec la plupart des cas d’utilisation dans notre application et ne se soucie pas de savoir si vous voulez uniquement le titre, l’image et le prix. Le backend construit le point de terminaison pour renvoyer l’entité complète du produit « juste au cas où » le frontend en aurait besoin à l’avenir.
Voyons un autre cas. Supposons que nous souhaitions afficher une liste de remises, afin que le backend crée le point de terminaison (par exemple, api/discount/{id}) pour restituer la remise en productId. Mais si je souhaite présenter un produit avec une offre, je dois faire plusieurs demandes. Le backend crée un point de terminaison pour le produit et un autre pour la remise. Que se passe-t-il si j’ai besoin uniquement de la remise et du titre du produit ? Ou la remise et l’image ?
Enfin et surtout, que se passe-t-il si je souhaite créer une application mobile pour obtenir les produits mais avec d’autres champs ou informations ? Le backend doit-il créer un point de terminaison pour le frontend et le mobile ?
Si nous voulons optimiser, réduire le bruit du trafic et rendre notre interface flexible pour demander uniquement les données réellement nécessaires, ou pour servir les appareils mobiles, il s’agit d’un problème réel. C’est à ce moment-là que GraphQL vient nous aider !
GraphQL est un langage de requête pour les API qui vous permet de demander exactement les données souhaitées, ni plus, ni moins.
Cela fonctionne comme un point de terminaison unique pour gérer toutes les requêtes et mutations (que j’expliquerai plus tard). GraphQL fournit un typage fort, de sorte que l’API décrit les données qu’elle peut renvoyer et les opérations disponibles, ce qui la rend plus efficace, empêche la récupération excessive et réduit les requêtes réseau.
Toutes ces fonctionnalités résolvent la plupart des problèmes lorsque nous souhaitons créer nos applications, en réduisant le nombre de requêtes et en permettant au client de prendre le contrôle de ce dont il a besoin, à quel moment. La meilleure façon d’apprendre est de faire, nous allons donc voir comment GraphQL nous aide à améliorer notre application Kendo Store existante. Faisons-le!
Configurer le projet
Tout d’abord, clonez notre projet existant, Kendo Store, en exécutant la commande git clone https://github.com/danywalls/graphql-and-angular.git. Il clone le projet dans la branche spécifique.
Ensuite, passez à graphql-and-angular/ répertoire et exécuter npm i pour installer toutes les dépendances.
dany@dany:~/lab$ git clonehttps://github.com/danywalls/graphql-and-angular.git
Cloning into 'graphql-and-angular'...
remote: Enumerating objects: 176, done.
remote: Counting objects: 100% (176/176), done.
remote: Compressing objects: 100% (111/111), done.
remote: Total 176 (delta 95), reused 113 (delta 59), pack-reused 0 (from 0)
Receiving objects: 100% (176/176), 276.55 KiB | 2.51 MiB/s, done.
Resolving deltas: 100% (95/95), done.
dany@dany:~/lab$ cd graphql-and-angular/
dany@dany:~/lab/graphql-and-angular$ npm i
Nous sommes prêts, alors voyons notre projet existant en exécutant ng serve dans la borne.
ng serve
Initial chunk files | Names | Raw size
main.js | main | 24.20 kB |
styles.css | styles | 96 bytes |
polyfills.js | polyfills | 95 bytes |
| Initial total | 24.39 kB
Application bundle generation complete. [1.242 seconds]
Watch mode enabled. Watching for file changes...
NOTE: Raw file sizes do not reflect development server per-request transformations.
➜ Local: http://localhost:4200/
➜ press h + enter to show help
Parfait. Notre application est en cours d’exécution, il est donc temps de voir ce qui se passe dans notre application. Tout d’abord, ouvrez votre navigateur et accédez à http://localhost:4000.
Accédez à http:localhost:4200 et appuyez sur F12 (ou ⌘ ⌥ i pour Mac) pour utiliser DevTools. Cliquez sur l’onglet « Réseau » (1), vérifiez le filtre « Récupérer » (2) et rechargez la page pour voir notre demande à fakestoreapi.
Cliquez ensuite sur la réponse du produit (3). Il est livré avec une gamme de produits et inclut toutes les propriétés liées à un produit. Mais cela semble être trop d’informations, plus que ce dont nous avons réellement besoin.
C’est à ce moment-là que vous commencez à penser à modifier le backend pour qu’il n’affiche que trois champs. Mais que se passe-t-il si nous voulons créer une nouvelle page affichant des produits avec des offres, en affichant uniquement l’image ?
L’interface utilisateur change fréquemment, de sorte que le backend apporte des modifications à chaque fois ou crée de nouveaux points de terminaison ? Ce n’est pas une solution évolutive, donc avant de demander des modifications au backend, concentrons-nous sur notre application et voyons ce dont nous avons réellement besoin.
De quelles données avons-nous besoin ?
Si nous jetons un coup d’œil à notre Kendo Store, il affiche une liste de produits dans une liste d’éléments de carte, et chaque élément de carte affiche une liste de détails de produit.
Si nous prenons une seconde pour voir de quelles informations nous avons réellement besoin pour afficher cette page, les données sont les mêmes pour chaque carte, donc les détails dont notre page a besoin sont l’image, le titre du produit, le prix et l’ID du produit (caché).
Maintenant, si vous comparez cela avec un seul élément du products réponse:
{
"id": 4,
"title": "Mens Casual Slim Fit",
"price": 15.99,
"description": "The color could be slightly different between on the screen and in practice. / Please note that body builds vary by person, therefore, detailed size information should be reviewed below on the product description.",
"category": "men's clothing",
"image": "https://fakestoreapi.com/img/71YXzeOuslL._AC_UY879_t.png",
"rating": {
"rate": 2.1,
"count": 430
}
},
Le back-end revient rating, category et description champs que je n’utilise pas. Cela crée du bruit et également plus de trafic réseau pour l’utilisateur et nos serveurs.
Les données de notre boutique doivent être simples : un objet ou une collection d’objets avec seulement title, price, image et id.
Nous pouvons considérer notre application comme un graphe, un réseau d’objets connectés. Parfois, ceux-ci ont des relations entre eux ou avec d’autres éléments, comme la navigation, qui proviennent du backend. La réponse de notre backend est comme notre graphique de données ou notre graphique d’application : c’est une manière courante dans GraphQL de parler des données d’une application.
Le graphe d’application fournit un ensemble de nœuds. GraphQL nous aide à représenter les données de notre application comme un ensemble de nœuds et d’arêtes pour notre application, pour établir ou non des relations entre eux. Et pour définir notre structure graphique, nous utilisons un schéma !
Qu’est-ce qu’un schéma GraphQL ?
Un schéma est un contrat, donc le schéma GraphQL est un contrat entre notre serveur et le client. Il définit ce que notre API GraphQL peut faire, comment le client (application ou mobile) demande ou interagit avec les données, fonctionnant comme une couche entre le serveur et le client, nous offrant une flexibilité pour les consommateurs et réduisant la complexité du backend.
Mais comment définir notre contrat ? Ne vous inquiétez pas, nous procéderons étape par étape. Pour définir notre schéma, nous utiliserons le langage de définition de schéma (SDL). Le schéma est au cœur de notre contrat, son travail est une collection d’objets avec des types et des propriétés (ou champs), définis dans un fichier TypeScript ou une extension .graphl.
Continuez à lire car nous allons construire notre schéma et notre serveur !
Les champs d’un schéma ont un type, comme string ou Int. Mais aussi, par exemple, on peut avoir le type Player avec un champ de type Stat avec des statistiques de performances du joueur. Par exemple:
export type Stat {
points: Int!
rebounds: Int!
steals: Int!
}
export type Player = {
id: Int!
name: String!
position: String
stats: [Stat]
}
De plus, le SDL nous permet d’ajouter des définitions supplémentaires pour nos entités, en utilisant """ guillemets triples au début de chaque type :
"""
The nba player with his stats
"""
export type Player = {
id: Int!
name: String!
position: String
"Player stats with points, rebounds and steals only"
stats: [Stat]
}
Maintenant que nous avons un aperçu d’un schéma GraphQL, construisons notre premier schéma en utilisant GraphQL et TypeScript !
Approfondissez-vous schéma et types.
Construire le schéma
Dans notre répertoire d’applications, créez un nouveau répertoire server; il contiendra tout ce qui concerne notre serveur GraphQL. Après avoir créé le répertoire, accédez au serveur avec le terminal et exécutez npm init -y et installer @apollo/server, graphql et graphql-tag forfaits.
🧐 Assurez-vous d’être situé dans le
serverannuaire.
npm install @apollo/server graphql and graphql-tag
added 77 packages, and audited 1284 packages in 8s
190 packages are looking for funding
run `npm fund` for details
2 low severity vulnerabilities
Ensuite, créez un src répertoire et, à l’intérieur, créez le schema.ts déposer. Pour créer notre schéma, importez gql depuis graphql-tag. Il fonctionne comme un littéral de modèle balisé, pour encapsuler les chaînes GraphQL telles que la définition du schéma et les chaînes GraphQL dans un format que les bibliothèques Apollo peuvent comprendre pour effectuer des opérations sur les schémas, et il permet également la coloration syntaxique.
Créons nos définitions de types typeDefs en définissant la valeur de gql. Dans le modèle, nous écrivons nos types Product et Rating comme dans l’exemple précédent.
import gql from "graphql-tag";
export const typeDefs = gql`
type Product {
id: ID!
title: String!
price: Float!
description: String
category: String
image: String
rating: Rating
}
type Rating {
rate: Float
count: Int
}
}`;
Excellent, notre Produit est désormais entièrement représenté dans notre schéma, mais attendez une seconde ! Comment pouvons-nous obtenir ces types avec nos données ?
Nous devons trouver un moyen d’indiquer au serveur GraphQL ce qu’il doit récupérer. Au lieu d’obtenir des données de plusieurs points de terminaison, comme le fait une API REST, GraphQL fournit un type spécial : Query!
Tapez la requête
Nous créons des types comme des objets et le type de requête est également comme un objet dont les champs fonctionnent comme des points de terminaison pour nous, nous permettant d’obtenir des données de GraphQL.
Pour créer notre requête, nous adoptons la même approche que gqlen ajoutant un autre type Query avec les champs pour chaque type de requête pour nos données.
Autorisons les applications à interroger les produits en créant un type Query et en ajoutant le champ products. Il renvoie une liste de produits non nullable products: [Product!]!. Le code ressemble beaucoup aux types :
type Query {
products:[ Product!]!
}
La version finale de notre schéma en schema.ts ça ressemble à :
import gql from 'graphql-tag';
export const typeDefs = gql`
type Product {
id: ID!
title: String!
price: Float!
description: String
category: String
image: String
rating: Rating
}
type Rating {
rate: Float
count: Int
}
type Query {
products:[ Product!]!
}
`;
Parfait, nous avons notre schéma prêt. Il est temps de créer notre serveur GraphQL !
Construire le serveur GraphQL
Nous voulons créer un serveur GraphQL en utilisant @apollo/server package (installé auparavant). Il fournit un ensemble de fonctions pour créer et configurer notre serveur GraphQL avec TypeScript, avec seulement quelques lignes de code, prêt pour le développement et la production.
Le serveur GraphQL nous aidera à gérer les requêtes GraphQL, à renvoyer les champs d’un schéma renseigné et à les valider sur notre schéma.
Avant de commencer, comme nous utilisons TypeScript, créez un fichier tsconfig en exécutant npx tsc --init dans le server annuaire.
Accédez au server/src créez le index.ts fichier et importer deux fonctions : ApolloServer depuis @apollo/server paquet et startStandaloneServer depuis @apollo/server/standalone:
import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
Ensuite, nous créons le startApolloServer fonction. À l’intérieur, créez une instance de ApolloServer et définissons notre typeDefinitions de la schema.ts.
Le serveur est configuré. Pour le démarrer, appelez la fonction startStandaloneServeren passant le serveur en paramètre. Ajoutez un console.log pour voir que tout fonctionne et n’oubliez pas d’appeler le startApolloServer fonction pour initialiser le serveur.
import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
import { typeDefs } from "./schema";
async function startApolloServer() {
const server = new ApolloServer({ typeDefs });
const { url } = await startStandaloneServer(server);
console.log(`
🚀 Server is running!
📭 Query at ${url}
`);
}
startApolloServer();
Ensuite, nous devons exécuter le serveur à l’aide d’un script npm. Ouvrez le package.json dans le répertoire du serveur et ajoutez un nouveau script « start ». À l’aide du package npx et ts-node, exécutez index.ts. votre package.json doit ressembler à ceci :
{
"name": "server",
"version": "1.0.0",
"description": "",
"scripts": {
"start": "npx ts-node src/index.ts"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Dans la course du terminal npm run startet vous devriez voir quelque chose comme :
npm run start
> server@1.0.0 start
> npx ts-node src/index.ts
🚀 Server is running at http://localhost:4000/
Ouvrez le serveur dans le navigateur sur le port 4000 (http://localhost:4000) et tada !! Nous avons trouvé l’Apollo Explorer. L’Apollo Explorer nous aide à interagir avec notre schéma et à exécuter plusieurs requêtes dessus.
La zone de documentation affiche la requête et les champs permettant d’obtenir des données. L’exemple de requête est livré avec tous les champs pour obtenir les données. Nous pouvons écrire un exemple de requête et sélectionner des champs pour notre requête comme id, image, price, title ou utilisez l’exemple et cliquez sur le bouton « Requête » et voyez les résultats.
🙁 POUSSER !! Cela montre une erreur ! Mais si nous lisons le message d’erreur « Impossible de renvoyer null pour le champ non nullable Query.products ».
Cela signifie que nous devons renvoyer certaines données car notre GraphQL n’est connecté à aucune source de données. Pour rendre cela amusant, nous pouvons configurer des données fictives pour que notre équipe continue de travailler avec l’interface utilisateur sans nous soucier de la source des données.
En savoir plus sur Explorateur d’Apollon.
Faux et moqueur
GraphQL est prêt avec un ensemble d’outils pour nous permettre de simuler notre contrat ou schéma avec les clients. Pour nous moquer de nos données, nous devons utiliser @graphql-tools/mock et @graphql-tools/schema forfaits. Ces packages fourniront des fonctions pour configurer notre serveur lorsque nous commencerons à modifier notre schéma avec des exemples de simulations, en appelant deux fonctions : addMocksToSchema et makeExecutableSchema.
Tout d’abord, installez les packages @graphql-tools/mock et @graphql-tools/schema. Dans le terminal, exécutez la commande suivante :
npm install @graphql-tools/mock @graphql-tools/schema
added 11 packages, and audited 12 packages in 3s
found 0 vulnerabilities
Parfait, il est maintenant temps d’apporter quelques modifications à notre serveur. Au lieu d’utiliser notre schéma par défaut, nous utiliserons la propriété schema pour modifier la façon dont nous initialisons le serveur Apollo. Créer un nouveau fichier schema-mocks.ts déposer; en haut de l’importation addMocksToSchema et makeExecutableSchema fonctions et typeDefs.
import {typeDefs} from "./schema";
import {makeExecutableSchema} from "@graphql-tools/schema";
import {addMocksToSchema} from "@graphql-tools/mock";
Ensuite, nous créons un nouveau schéma en utilisant makeExecutableSchemaen passant en paramètre typeDefs depuis schema.ts.
import {typeDefs} from "./schema";
import {makeExecutableSchema} from "@graphql-tools/schema";
import {addMocksToSchema} from "@graphql-tools/mock";
const schema = makeExecutableSchema({typeDefs});
Définir un nouveau fichier mocks objet avec l’exemple de Product sur la base de nos définitions de types pour nos clients lors de la demande de données.
const mocks = {
Product: () => ({
id: `1`,
title: 'Mock Product',
price: 15.2,
description: 'This is a mocked product description.',
category: 'Electronics',
image: 'https://via.placeholder.com/150',
rating: {
rate: 5,
count: 3,
},
}),
};
Pour fournir le serveur aux simulations, utilisez le nouveau schéma avec le résultat de addMocksToSchema fonction.
export const schemaWithMocks = addMocksToSchema({schema, mocks});
La version finale ressemble à :
import {typeDefs} from "./schema";
import {makeExecutableSchema} from "@graphql-tools/schema";
import {addMocksToSchema} from "@graphql-tools/mock";
const schema = makeExecutableSchema({typeDefs});
const mocks = {
Product: () => ({
id: `1`,
title: 'Mock Product',
price: 15.2,
description: 'This is a mocked product description.',
category: 'Electronics',
image: 'https://via.placeholder.com/150',
rating: {
rate: 5,
count: 3,
},
}),
};
export const schemaWithMocks = addMocksToSchema({schema, mocks});
Enfin, nous allons effectuer un petit changement dans le ApolloServeren passant le schemaWithMocks fonction. Ouvrir index.tsimportez le schemaWithMocks fonction et définissez-la sur la propriété de schéma.
import {ApolloServer} from "@apollo/server";
import {startStandaloneServer} from "@apollo/server/standalone";
import {schemaWithMocks} from "./schema-mock";
async function startApolloServer() {
const server = new ApolloServer({
schema: schemaWithMocks
});
const {url} = await startStandaloneServer(server);
console.log(`
🚀 Server is running at ${url}
`);
}
startApolloServer();
Enregistrez les modifications et rechargez notre serveur. Il est prêt à interroger avec des données fictives, nous sommes donc désormais entièrement libres d’écrire des requêtes personnalisées, comme la sélection de plusieurs champs ou d’un seul pour nos requêtes.
Résumer
Nous avons appris les problèmes liés à la création d’une application basée sur les données, à quel point il est facile de configurer et de configurer notre propre serveur GraphQL à l’aide du client Apollo et les avantages de l’interrogation des données et de la définition des types et des requêtes.
Nous avons vu quand et pourquoi utiliser GraphQL, qui permet aux clients de demander exactement les données qu’ils souhaitent au serveur. Et, en plus de cela, nous avons appris comment configurer des requêtes fictives pour jouer avec l’explorateur GraphQL.
Dans le chapitre suivant, nous allons apprendre comment intégrer Apollo Client à Angular et comment interroger uniquement les champs obligatoires dans nos composants !
Source link

