Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.
Le schéma GraphQL est la base de toute implémentation de serveur GraphQL. Chaque GraphQL API est défini par un schéma unique qui contient des types et des champs décrivant la manière dont les données des requêtes seront renseignées. Les données qui vous circulent API et les opérations effectuées doivent être validées par rapport au schéma.
En général, le système de type GraphQL
AWS AppSync vous permet de définir et de configurer des schémas GraphQL. La section suivante décrit comment créer des schémas GraphQL à partir de zéro à l'aide AWS AppSync des services.
Structuration d'un schéma GraphQL
Astuce
Nous vous recommandons de consulter la section Schémas avant de continuer.
GraphQL est un outil puissant pour implémenter API des services. Selon le site Web de GraphQL,
« GraphQL est un langage de requête APIs et un environnement d'exécution permettant de répondre à ces requêtes avec vos données existantes. GraphQL fournit une description complète et compréhensible des données qu'il contientAPI, donne aux clients le pouvoir de demander exactement ce dont ils ont besoin, rien de plus, facilite l'évolution APIs au fil du temps et met à disposition de puissants outils de développement. «
Cette section couvre la toute première partie de votre implémentation GraphQL, le schéma. À l'aide de la citation ci-dessus, un schéma joue le rôle de « fournir une description complète et compréhensible des données contenues dans votre API ». En d'autres termes, un schéma GraphQL est une représentation textuelle des données, des opérations et des relations entre les données de votre service. Le schéma est considéré comme le point d'entrée principal pour l'implémentation de votre service GraphQL. Comme on pouvait s'y attendre, c'est souvent l'une des premières choses que vous réalisez dans votre projet. Nous vous recommandons de consulter la section Schémas avant de continuer.
Pour citer la section Schémas, les schémas GraphQL sont écrits dans le langage de définition du schéma (). SDL SDLest composé de types et de champs dotés d'une structure établie :
-
Types : Les types sont la façon dont GraphQL définit la forme et le comportement des données. GraphQL prend en charge une multitude de types qui seront expliqués plus loin dans cette section. Chaque type défini dans votre schéma contiendra sa propre portée. Le champ d'application comportera un ou plusieurs champs pouvant contenir une valeur ou une logique qui sera utilisée dans votre service GraphQL. Les types remplissent de nombreux rôles différents, les plus courants étant les objets ou les scalaires (types de valeurs primitives).
-
Champs : les champs existent dans le cadre d'un type et contiennent la valeur demandée au service GraphQL. Elles sont très similaires aux variables d'autres langages de programmation. La forme des données que vous définissez dans vos champs déterminera la manière dont les données sont structurées lors d'une opération de demande/réponse. Cela permet aux développeurs de prévoir ce qui sera renvoyé sans savoir comment le backend du service est implémenté.
Les schémas les plus simples contiendront trois catégories de données différentes :
-
Racines du schéma : les racines définissent les points d'entrée de votre schéma. Il indique les champs qui effectueront certaines opérations sur les données, telles que l'ajout, la suppression ou la modification de quelque chose.
-
Types : il s'agit de types de base utilisés pour représenter la forme des données. Vous pouvez presque les considérer comme des objets ou des représentations abstraites de quelque chose avec des caractéristiques définies. Par exemple, vous pouvez créer un
Person
objet représentant une personne dans une base de données. Les caractéristiques de chaque personne seront définies dans les champsPerson
as. Ils peuvent être n'importe quoi comme le nom, l'âge, le travail, l'adresse de la personne, etc. -
Types d'objets spéciaux : il s'agit des types qui définissent le comportement des opérations dans votre schéma. Chaque type d'objet spécial est défini une fois par schéma. Ils sont d'abord placés dans la racine du schéma, puis définis dans le corps du schéma. Chaque champ d'un type d'objet spécial définit une opération unique à implémenter par votre résolveur.
Pour mettre les choses en perspective, imaginez que vous créez un service qui stocke les auteurs et les livres qu'ils ont écrits. Chaque auteur a un nom et une liste de livres qu'il a écrits. Chaque livre a un nom et une liste d'auteurs associés. Nous voulons également pouvoir ajouter ou récupérer des livres et des auteurs. Voici une UML représentation simple de cette relation :

Dans GraphQL, les entités Author
et B Book
représentent deux types d'objets différents dans votre schéma :
type Author {
}
type Book {
}
Author
contient authorName
etBooks
, tandis que Book
contient bookName
etAuthors
. Ceux-ci peuvent être représentés sous forme de champs correspondant à vos types :
type Author {
authorName: String
Books: [Book]
}
type Book {
bookName: String
Authors: [Author]
}
Comme vous pouvez le constater, les représentations de type sont très proches du diagramme. Cependant, c'est dans les méthodes que cela devient un peu plus délicat. Ils seront placés dans l'un des rares types d'objets spéciaux sous forme de champ. La catégorisation des objets spéciaux dépend de leur comportement. GraphQL contient trois types d'objets spéciaux fondamentaux : les requêtes, les mutations et les abonnements. Pour plus d'informations, consultez la section Objets spéciaux.
Parce que getAuthor
getBook
les deux demandent des données, elles seront placées dans un type d'objet Query
spécial :
type Author {
authorName: String
Books: [Book]
}
type Book {
bookName: String
Authors: [Author]
}
type Query {
getAuthor(authorName: String): Author
getBook(bookName: String): Book
}
Les opérations sont liées à la requête, elle-même liée au schéma. L'ajout d'une racine de schéma définira le type d'objet spécial (Query
dans ce cas) comme l'un de vos points d'entrée. Cela peut être fait à l'aide du schema
mot clé :
schema {
query: Query
}
type Author {
authorName: String
Books: [Book]
}
type Book {
bookName: String
Authors: [Author]
}
type Query {
getAuthor(authorName: String): Author
getBook(bookName: String): Book
}
Examinez les deux dernières méthodes addAuthor
et ajoutez addBook
des données à votre base de données, afin qu'elles soient définies dans un type d'objet Mutation
spécial. Cependant, depuis la page Types, nous savons également que les entrées faisant directement référence à des objets ne sont pas autorisées car il s'agit uniquement de types de sortie. Dans ce cas, nous ne pouvons pas utiliser Author
ouBook
, nous devons donc créer un type de saisie avec les mêmes champs. Dans cet exemple, nous avons ajouté AuthorInput
etBookInput
, qui acceptent tous deux les mêmes champs de leurs types respectifs. Ensuite, nous créons notre mutation en utilisant les entrées comme paramètres :
schema {
query: Query
mutation: Mutation
}
type Author {
authorName: String
Books: [Book]
}
input AuthorInput {
authorName: String
Books: [BookInput]
}
type Book {
bookName: String
Authors: [Author]
}
input BookInput {
bookName: String
Authors: [AuthorInput]
}
type Query {
getAuthor(authorName: String): Author
getBook(bookName: String): Book
}
type Mutation {
addAuthor(input: [BookInput]): Author
addBook(input: [AuthorInput]): Book
}
Passons en revue ce que nous venons de faire :
-
Nous avons créé un schéma avec les
Author
typesBook
et pour représenter nos entités. -
Nous avons ajouté les champs contenant les caractéristiques de nos entités.
-
Nous avons ajouté une requête pour récupérer ces informations dans la base de données.
-
Nous avons ajouté une mutation pour manipuler les données de la base de données.
-
Nous avons ajouté des types d'entrée pour remplacer les paramètres de nos objets dans la mutation afin de respecter les règles de GraphQL.
-
Nous avons ajouté la requête et la mutation à notre schéma racine afin que l'implémentation GraphQL comprenne l'emplacement du type de racine.
Comme vous pouvez le constater, le processus de création d'un schéma repose sur de nombreux concepts issus de la modélisation des données (en particulier de la modélisation de base de données) en général. Vous pouvez considérer le schéma comme s'adaptant à la forme des données provenant de la source. Il sert également de modèle que le résolveur implémentera. Dans les sections suivantes, vous allez apprendre à créer un schéma à l'aide de divers outils et services AWS basés sur des outils.
Note
Les exemples présentés dans les sections suivantes ne sont pas destinés à être exécutés dans une application réelle. Ils ne sont là que pour présenter les commandes afin que vous puissiez créer vos propres applications.
Création de schémas
Votre schéma se trouvera dans un fichier appeléschema.graphql
. AWS AppSync permet aux utilisateurs de créer de nouveaux schémas pour leur APIs GraphQL en utilisant différentes méthodes. Dans cet exemple, nous allons créer un espace vide API avec un schéma vide.
-
Connectez-vous à la AppSyncconsole AWS Management Console et ouvrez-la
. -
Dans le tableau de bord, choisissez Create API.
-
Dans APIles options, choisissez GraphQL APIs, Design from scratch, puis Next.
-
Pour APIle nom, modifiez le nom prérempli en fonction des besoins de votre application.
-
Pour les coordonnées, vous pouvez saisir un point de contact afin d'identifier un responsable pour leAPI. Il s'agit d'un champ facultatif.
-
Sous APIConfiguration privée, vous pouvez activer les API fonctionnalités privées. Un compte privé n'est API accessible qu'à partir d'un point de VPC terminaison configuré (VPCE). Pour plus d'informations, voir Privé APIs.
Nous ne recommandons pas d'activer cette fonctionnalité pour cet exemple. Choisissez Next après avoir examiné vos entrées.
-
-
Sous Créer un type GraphQL, vous pouvez choisir de créer une table DynamoDB à utiliser comme source de données ou de l'ignorer pour le faire ultérieurement.
Pour cet exemple, choisissez Create GraphQL resources later. Nous allons créer une ressource dans une section séparée.
-
Passez en revue vos entrées, puis choisissez Créer API.
-
-
Vous serez dans le tableau de bord de votre compteAPI. Vous pouvez le savoir car le nom API du 'sera affiché en haut du tableau de bord. Si ce n'est pas le cas, vous pouvez sélectionner APIsdans la barre latérale, puis choisir votre API dans le APIstableau de bord.
-
Dans la barre latérale située sous votre API nom, choisissez Schema.
-
-
Dans l'éditeur de schéma, vous pouvez configurer votre
schema.graphql
fichier. Il peut être vide ou rempli de types générés à partir d'un modèle. Sur la droite, vous avez la section Résolveurs pour associer des résolveurs aux champs de votre schéma. Nous n'examinerons pas les résolveurs dans cette section.
Ajouter des types aux schémas
Maintenant que vous avez ajouté votre schéma, vous pouvez commencer à ajouter vos types d'entrée et de sortie. Notez que les types présentés ici ne doivent pas être utilisés dans le code réel ; ce ne sont que des exemples destinés à vous aider à comprendre le processus.
Nous allons d'abord créer un type d'objet. Dans le code réel, il n'est pas nécessaire de commencer par ces types. Vous pouvez créer le type que vous voulez à tout moment, à condition de respecter les règles et la syntaxe de GraphQL.
Note
Les prochaines sections utiliseront l'éditeur de schéma, alors gardez-le ouvert.
-
Vous pouvez créer un type d'objet en utilisant le
type
mot-clé associé au nom du type :type
Type_Name_Goes_Here
{}Dans le champ d'application du type, vous pouvez ajouter des champs qui représentent les caractéristiques de l'objet :
type
Type_Name_Goes_Here
{ # Add fields here }Voici un exemple :
type
Obj_Type_1
{id: ID! title: String date: AWSDateTime
}Note
Dans cette étape, nous avons ajouté un type d'objet générique avec un
id
champ obligatoire stocké sous formeID
, untitle
champ stocké sous forme de et undate
champ stocké sous forme deAWSDateTime
.String
Pour consulter la liste des types et des champs et leur fonction, reportez-vous à la section Schémas. Pour voir la liste des scalaires et leur fonction, consultez la référence Type.
Le type d'objetAWSDateTime
en plus des scalaires GraphQL de base. En outre, tout champ se terminant par un point d'exclamation est obligatoire.
Le type ID
scalaire en particulier est un identifiant unique qui peut être String
soitInt
. Vous pouvez les contrôler dans le code de votre résolveur pour une attribution automatique.
Il existe des similitudes entre les types d'objets spéciaux Query
et les types d'objets « ordinaires », comme dans l'exemple ci-dessus, en ce sens qu'ils utilisent tous deux le type
mot-clé et sont considérés comme des objets. Cependant, pour les types d'objets spéciaux (Query
Mutation
,, etSubscription
), leur comportement est très différent car ils sont exposés comme points d'entrée pour votreAPI. Ils visent également à façonner les opérations plutôt que les données. Pour plus d'informations, consultez la section Les types de requête et de mutation
En ce qui concerne les types d'objets spéciaux, l'étape suivante pourrait consister à en ajouter un ou plusieurs pour effectuer des opérations sur les données mises en forme. Dans un scénario réel, chaque schéma GraphQL doit au moins avoir un type de requête racine pour demander des données. Vous pouvez considérer la requête comme l'un des points d'entrée (ou points de terminaison) de votre serveur GraphQL. Ajoutons une requête à titre d'exemple.
-
Pour créer une requête, vous pouvez simplement l'ajouter au fichier de schéma comme n'importe quel autre type. Une requête nécessiterait un
Query
type et une entrée à la racine comme ceci :schema { query:
Name_of_Query
} typeName_of_Query
{ # Add field operation here }Notez que
Name_of_Query
dans un environnement de production sera simplement appeléQuery
dans la plupart des cas. Nous vous recommandons de le maintenir à cette valeur. Dans le type de requête, vous pouvez ajouter des champs. Chaque champ effectuera une opération dans la demande. Par conséquent, la plupart de ces champs, sinon tous, seront attachés à un résolveur. Cependant, cela ne nous intéresse pas dans cette section. En ce qui concerne le format de l'opération sur le terrain, cela pourrait ressembler à ceci :Name_of_Query(params): Return_Type
# version with paramsName_of_Query: Return_Type
# version without paramsVoici un exemple :
schema { query: Query } type Query {
getObj: [Obj_Type_1]
} type Obj_Type_1 { id: ID! title: String date: AWSDateTime }Note
Dans cette étape, nous avons ajouté un
Query
type et l'avons défini dans notreschema
racine. NotreQuery
type a défini ungetObj
champ qui renvoie une liste d'Obj_Type_1
objets. Notez queObj_Type_1
c'est l'objet de l'étape précédente. Dans le code de production, vos opérations sur le terrain travailleront normalement avec des données façonnées par des objets tels queObj_Type_1
. De plus, les champs degetObj
ce type auront normalement un résolveur pour exécuter la logique métier. Cela sera traité dans une autre section.En outre, ajoute AWS AppSync automatiquement une racine de schéma lors des exportations. Techniquement, vous n'avez donc pas besoin de l'ajouter directement au schéma. Notre service traitera automatiquement les schémas dupliqués. Nous l'ajoutons ici en tant que meilleure pratique.
Vous avez maintenant vu un exemple de création d'objets et d'objets spéciaux (requêtes). Vous avez également vu comment ils peuvent être interconnectés pour décrire les données et les opérations. Vous pouvez avoir des schémas contenant uniquement la description des données et une ou plusieurs requêtes. Cependant, nous aimerions ajouter une autre opération pour ajouter des données à la source de données. Nous allons ajouter un autre type d'objet spécial appelé Mutation
qui modifie les données.
-
Une mutation sera appelée
Mutation
. Par exempleQuery
, les opérations de terrain qu'Mutation
il contient décriront une opération et seront associées à un résolveur. Notez également que nous devons le définir à laschema
racine car il s'agit d'un type d'objet spécial. Voici un exemple de mutation :schema {
mutation: Name_of_Mutation
} typeName_of_Mutation
{ # Add field operation here }Une mutation typique sera répertoriée à la racine comme une requête. La mutation est définie à l'aide du
type
mot clé associé au nom.Name_of_Mutation
sera généralement appeléMutation
, nous vous recommandons donc de continuer ainsi. Chaque champ effectuera également une opération. En ce qui concerne le format de l'opération sur le terrain, cela pourrait ressembler à ceci :Name_of_Mutation(params): Return_Type # version with params Name_of_Mutation: Return_Type # version without params
Voici un exemple :
schema { query: Query
mutation: Mutation
} type Obj_Type_1 { id: ID! title: String date: AWSDateTime } type Query { getObj: [Obj_Type_1] } type Mutation {addObj(id: ID!, title: String, date: AWSDateTime): Obj_Type_1
}Note
Dans cette étape, nous avons ajouté un
Mutation
type avec unaddObj
champ. Résumons le rôle de ce champ :addObj(id: ID!, title: String, date: AWSDateTime): Obj_Type_1
addObj
utilise l'Obj_Type_1
objet pour effectuer une opération. Cela est évident en raison des champs, mais la syntaxe le prouve dans le type de: Obj_Type_1
retour. À l'intérieuraddObj
, il accepte lesdate
champsid
,title
, et de l'Obj_Type_1
objet en tant que paramètres. Comme vous pouvez le constater, cela ressemble beaucoup à une déclaration de méthode. Cependant, nous n'avons pas encore décrit le comportement de notre méthode. Comme indiqué précédemment, le schéma est uniquement là pour définir quelles seront les données et les opérations, et non leur mode de fonctionnement. La mise en œuvre de la véritable logique métier interviendra plus tard lorsque nous créerons nos premiers résolveurs.Une fois que vous avez terminé avec votre schéma, il est possible de l'exporter sous forme de
schema.graphql
fichier. Dans l'éditeur de schéma, vous pouvez choisir Exporter le schéma pour télécharger le fichier dans un format pris en charge.En outre, ajoute AWS AppSync automatiquement une racine de schéma lors des exportations. Techniquement, vous n'avez donc pas besoin de l'ajouter directement au schéma. Notre service traitera automatiquement les schémas dupliqués. Nous l'ajoutons ici en tant que meilleure pratique.
Considérations facultatives - Utilisation des énumérations comme statuts
À ce stade, vous savez comment créer un schéma de base. Cependant, vous pouvez ajouter de nombreux éléments pour améliorer les fonctionnalités du schéma. Une chose courante dans les applications est l'utilisation d'énumérations comme statuts. Vous pouvez utiliser une énumération pour forcer le choix d'une valeur spécifique d'un ensemble de valeurs lors de l'appel. C'est bon pour des choses dont vous savez qu'elles ne changeront pas radicalement sur de longues périodes. Hypothétiquement parlant, nous pourrions ajouter une énumération qui renvoie le code d'état ou une chaîne dans la réponse.
Par exemple, supposons que nous créons une application de réseau social qui stocke les données de publication d'un utilisateur dans le backend. Notre schéma contient un Post
type qui représente les données d'une publication individuelle :
type Post {
id: ID!
title: String
date: AWSDateTime
poststatus: PostStatus
}
Notre message Post
title
contiendra une publication unique id
et une énumération appelée PostStatus
qui représente l'état de la publication telle qu'elle est traitée par l'application. date
Pour nos opérations, nous aurons une requête qui renverra toutes les données de publication :
type Query {
getPosts: [Post]
}
Nous aurons également une mutation qui ajoutera des publications à la source de données :
type Mutation {
addPost(id: ID!, title: String, date: AWSDateTime, poststatus: PostStatus): Post
}
En regardant notre schéma, l'PostStatus
énumération peut avoir plusieurs statuts. Nous souhaiterons peut-être que les trois états de base soient appelés success
(post traité avec succès), pending
(post en cours de traitement) et error
(post incapable d'être traité). Pour ajouter l'énumération, nous pourrions faire ceci :
enum PostStatus {
success
pending
error
}
Le schéma complet pourrait ressembler à ceci :
schema {
query: Query
mutation: Mutation
}
type Post {
id: ID!
title: String
date: AWSDateTime
poststatus: PostStatus
}
type Mutation {
addPost(id: ID!, title: String, date: AWSDateTime, poststatus: PostStatus): Post
}
type Query {
getPosts: [Post]
}
enum PostStatus {
success
pending
error
}
Si un utilisateur ajoute un Post
dans l'application, l'addPost
opération sera appelée pour traiter ces données. Au fur et à mesure que le résolveur attaché addPost
traite les données, il les met continuellement à jour en poststatus
fonction de l'état de l'opération. Lorsqu'il est demandé, le Post
testament contiendra le statut final des données. N'oubliez pas que nous ne décrivons que la manière dont nous voulons que les données fonctionnent dans le schéma. Nous avons beaucoup d'hypothèses quant à la mise en œuvre de nos résolveurs, qui mettront en œuvre la logique métier réelle pour traiter les données afin de répondre à la demande.
Considérations facultatives - Abonnements
Les abonnements AWS AppSync sont invoqués en réponse à une mutation. Vous configurez cela avec un type Subscription
et une directive @aws_subscribe()
du schéma pour signifier quelles mutations appellent un ou plusieurs abonnements. Pour plus d'informations sur la configuration des abonnements, consultez la section Données en temps réel.
Considérations facultatives - Relations et pagination
Supposons que vous en ayez Posts
stocké un million dans une table DynamoDB et que vous souhaitiez renvoyer certaines de ces données. Cependant, l'exemple de requête donné ci-dessus ne renvoie que tous les messages. Vous ne voudriez pas les récupérer tous à chaque fois que vous faites une demande. Au lieu de cela, vous devriez les paginer
-
Dans le
getPosts
champ, ajoutez deux arguments d'entrée :nextToken
(itérateur) etlimit
(limite d'itération). -
Ajoutez un nouveau
PostIterator
type contenantPosts
(récupère la liste desPost
objets) et des champsnextToken
(itérateur). -
getPosts
Modifiez-le pour qu'il renvoiePostIterator
et non une liste d'Post
objets.
schema {
query: Query
mutation: Mutation
}
type Post {
id: ID!
title: String
date: AWSDateTime
poststatus: PostStatus
}
type Mutation {
addPost(id: ID!, title: String, date: AWSDateTime, poststatus: PostStatus): Post
}
type Query {
getPosts(limit: Int, nextToken: String): PostIterator
}
enum PostStatus {
success
pending
error
}
type PostIterator {
posts: [Post]
nextToken: String
}
Le PostIterator
type vous permet de renvoyer une partie de la liste des Post
objets et un nextToken
pour obtenir la partie suivante. À l'intérieurPostIterator
, il y a une liste d'Post
items ([Post]
) qui est renvoyée avec un jeton de pagination (nextToken
). En AWS AppSync, il serait connecté à Amazon DynamoDB via un résolveur et généré automatiquement sous forme de jeton chiffré. Cela convertir la valeur de l'argument limit
en paramètre maxResults
et l'argument nextToken
en paramètre exclusiveStartKey
. Pour des exemples et des exemples de modèles intégrés dans la AWS AppSync console, voir Resolver reference (JavaScript).