

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.

# Schémas GraphQL
<a name="schema-components"></a>

Le schéma GraphQL est la base d'une API GraphQL. Il sert de modèle qui définit la forme de vos données. Il s'agit également d'un contrat entre votre client et votre serveur qui définit la manière dont vos données seront récupérées et and/or modifiées.

Les schémas GraphQL sont écrits dans le langage SDL (*Schema Definition Language*). SDL est 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 request/response opération. Cela permet aux développeurs de prévoir ce qui sera renvoyé sans savoir comment le backend du service est implémenté.

Pour visualiser à quoi ressemblerait un schéma, examinons le contenu d'un schéma GraphQL simple. Dans le code de production, votre schéma se trouve généralement dans un fichier appelé `schema.graphql` ou`schema.json`. Supposons que nous étudions un projet qui implémente un service GraphQL. Ce projet stocke les données du personnel de l'entreprise, et le `schema.graphql` fichier est utilisé pour récupérer les données sur le personnel et ajouter du nouveau personnel à une base de données. Le code peut ressembler à ceci :

------
#### [ schema.graphql ]

```
type Person {                                  
   id: ID!
   name: String                                  
   age: Int
}
type Query {                                   
  people: [Person]
}
type Mutation {
  addPerson(id: ID!, name: String, age: Int): Person
}
```

------

Nous pouvons voir qu'il existe trois types définis dans le schéma :`Person`,`Query`, et`Mutation`. En regardant`Person`, nous pouvons deviner qu'il s'agit du modèle d'une instance d'un employé de l'entreprise, ce qui ferait de ce type un objet. À l'intérieur de son champ d'application`id`, nous voyons`name`, et`age`. Ce sont les champs qui définissent les propriétés d'un`Person`. Cela signifie que notre source de données stocke chacun `Person` d'eux `name` en tant que type `String` scalaire (primitif) et `age` en tant que type `Int` scalaire (primitif). Il `id` agit comme un identifiant spécial et unique pour chacun d'entre eux`Person`. Il s'agit également d'une valeur obligatoire, comme indiqué par le `!` symbole.

Les deux types d'objets suivants se comportent différemment. GraphQL réserve quelques mots clés pour des types d'objets spéciaux qui définissent la manière dont les données seront renseignées dans le schéma. Un `Query` type récupérera les données de la source. Dans notre exemple, notre requête peut récupérer `Person` des objets d'une base de données. Cela peut vous rappeler des `GET` opérations RESTful terminologiques. A `Mutation` modifiera les données. Dans notre exemple, notre mutation peut ajouter d'autres `Person` objets à la base de données. Cela peut vous rappeler des opérations qui changent d'état, comme `PUT` ou`POST`. Les comportements de tous les types d'objets spéciaux seront expliqués plus loin dans cette section.

Supposons que `Query` dans notre exemple, quelque chose soit extrait de la base de données. Si nous examinons les champs de`Query`, nous voyons un champ appelé`people`. La valeur de son champ est`[Person]`. Cela signifie que nous voulons récupérer une instance de `Person` dans la base de données. Cependant, l'ajout de crochets signifie que nous voulons renvoyer une liste de toutes les `Person` instances et pas seulement une instance spécifique.

Le `Mutation` type est chargé d'effectuer des opérations de changement d'état telles que la modification des données. Une mutation est chargée d'effectuer une opération de changement d'état sur la source de données. Dans notre exemple, notre mutation contient une opération appelée `addPerson` qui ajoute un nouvel `Person` objet à la base de données. La mutation utilise un `Person` et attend une entrée pour les `age` champs `id``name`, et.

À ce stade, vous vous demandez peut-être comment `addPerson` fonctionnent de telles opérations sans implémentation de code, étant donné qu'elles sont censées avoir un certain comportement et ressemblent beaucoup à une fonction avec un nom de fonction et des paramètres. Actuellement, cela ne fonctionne pas car un schéma ne sert que de déclaration. Pour implémenter le comportement de`addPerson`, il faudrait y ajouter un résolveur. Un résolveur est une unité de code exécutée chaque fois que le champ associé (dans ce cas, l'`addPerson`opération) est appelé. Si vous souhaitez utiliser une opération, vous devrez ajouter l'implémentation du résolveur à un moment donné. D'une certaine manière, vous pouvez considérer l'opération du schéma comme la déclaration de fonction et le résolveur comme la définition. Les résolveurs seront expliqués dans une section différente.

Cet exemple montre uniquement les méthodes les plus simples utilisées par un schéma pour manipuler les données. Vous créez des applications complexes, robustes et évolutives en tirant parti des fonctionnalités de GraphQL et. AWS AppSync Dans la section suivante, nous définirons les différents types et comportements de champ que vous pouvez utiliser dans votre schéma.

# Types de GraphQL
<a name="graphql-types"></a>

GraphQL prend en charge de nombreux types différents. Comme vous l'avez vu dans la section précédente, les types définissent la forme ou le comportement de vos données. Ils sont les éléments de base d'un schéma GraphQL. 

Les types peuvent être classés en entrées et en sorties. Les entrées sont des types autorisés à être transmis comme argument pour les types d'objets spéciaux (`Query`,, etc.)`Mutation`, tandis que les types de sortie sont strictement utilisés pour stocker et renvoyer des données. Vous trouverez ci-dessous une liste des types et de leurs catégories :
+ **Objets** : un objet contient des champs décrivant une entité. Par exemple, un objet peut être quelque chose comme un `book` avec des champs décrivant ses caractéristiques comme `authorName``publishingYear`, etc. Ce sont strictement des types de sortie.
+ **Scalaires** : ce sont des types primitifs tels que int, string, etc. Ils sont généralement affectés à des champs. En utilisant le `authorName` champ comme exemple, on pourrait lui attribuer le `String` scalaire pour stocker un nom tel que « John Smith ». Les scalaires peuvent être des types d'entrée et de sortie.
+ **Entrées** : Les entrées vous permettent de transmettre un groupe de champs en tant qu'argument. Leur structure est très similaire à celle des objets, mais ils peuvent être transmis en tant qu'arguments à des objets spéciaux. Les entrées vous permettent de définir des scalaires, des énumérations et d'autres entrées dans son champ d'application. Les entrées ne peuvent être que des types d'entrée.
+ **Objets spéciaux** : les objets spéciaux effectuent des opérations de changement d'état et effectuent l'essentiel du travail. Il existe trois types d'objets spéciaux : requête, mutation et abonnement. Les requêtes récupèrent généralement des données ; les mutations manipulent les données ; les abonnements ouvrent et maintiennent une connexion bidirectionnelle entre les clients et les serveurs pour une communication constante. Les objets spéciaux ne sont ni en entrée ni en sortie étant donné leur fonctionnalité.
+ **Enums : Les** énumérations sont des listes prédéfinies de valeurs légales. Si vous appelez une énumération, ses valeurs ne peuvent être que celles définies dans son champ d'application. Par exemple, si vous aviez une énumération intitulée `trafficLights` représentant une liste de feux de circulation, elle pourrait avoir des valeurs telles que `redLight` et `greenLight` mais non`purpleLight`. Un vrai feu de signalisation n'aura qu'un nombre limité de signaux. Vous pouvez donc utiliser l'énumération pour les définir et les forcer à être les seules valeurs légales lors du référencement`trafficLight`. Les énumérations peuvent être des types d'entrée et de sortie.
+ **Unions/interfaces** : les syndicats vous permettent de renvoyer un ou plusieurs éléments dans une demande en fonction des données demandées par le client. Par exemple, si vous aviez un `Book` type avec un `title` champ et un `Author` type avec un `name` champ, vous pourriez créer une union entre les deux types. Si votre client souhaitait rechercher dans une base de données l'expression « Jules César », le syndicat pourrait renvoyer *Jules César* (la pièce de William Shakespeare) du `Book` `title` et *Jules César* (l'auteur de *Commentarii de Bello* Gallico) du. `Author` `name` Les unions ne peuvent être que des types de sortie.

  Les interfaces sont des ensembles de champs que les objets doivent implémenter. Cela ressemble un peu aux interfaces des langages de programmation tels que Java où vous devez implémenter les champs définis dans l'interface. Supposons, par exemple, que vous ayez créé une interface appelée `Book` contenant un `title` champ. Supposons que vous ayez créé par la suite un type appelé « `Novel` that implemented »`Book`. Vous `Novel` devrez inclure un `title` champ. Cependant, vous `Novel` pouvez également inclure d'autres champs ne figurant pas dans l'interface, tels que `pageCount` ou`ISBN`. Les interfaces ne peuvent être que des types de sortie.

Les sections suivantes expliquent le fonctionnement de chaque type dans GraphQL.

## Objets
<a name="object-components"></a>

Les objets GraphQL sont le type principal que vous verrez dans le code de production. Dans GraphQL, vous pouvez considérer un objet comme un regroupement de différents champs (similaires aux variables d'autres langages), chaque champ étant défini par un type (généralement un scalaire ou un autre objet) pouvant contenir une valeur. Les objets représentent une unité de données qui peut retrieved/manipulated provenir de l'implémentation de votre service.

Les types d'objets sont déclarés à l'aide du `Type` mot clé. Modifions légèrement notre exemple de schéma :

```
type Person {
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}
```

Les types d'objets présentés ici sont `Person` et`Occupation`. Chaque objet possède ses propres champs avec ses propres types. L'une des fonctionnalités de GraphQL est la possibilité de définir d'autres types de champs. Vous pouvez voir que le `occupation` champ `Person` contient un type d'`Occupation`objet. Nous pouvons établir cette association car GraphQL ne fait que décrire les données et non l'implémentation du service.

## Scalaires
<a name="scalar-components"></a>

Les scalaires sont essentiellement des types primitifs qui contiennent des valeurs. Dans AWS AppSync, il existe deux types de scalaires : les scalaires GraphQL par défaut et les scalaires AWS AppSync . Les scalaires sont généralement utilisés pour stocker des valeurs de champs dans des types d'objets. Les types GraphQL par défaut incluent`Int`, `Float` `String``Boolean`, et. `ID` Reprenons l'exemple précédent :

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}
```

En distinguant les `title` champs `name` et, les deux contiennent un `String` scalaire. `Name`pourrait renvoyer une valeur de chaîne comme « `John Smith` » et le titre pourrait renvoyer quelque chose comme « `firefighter` ». Certaines implémentations de GraphQL prennent également en charge les scalaires personnalisés utilisant le `Scalar` mot-clé et implémentant le comportement du type. Cependant, les scalaires personnalisés **ne sont AWS AppSync actuellement pas pris en charge**. Pour une liste des scalaires, voir [Types de scalaires](https://docs.aws.amazon.com//appsync/latest/devguide/scalars.html) dans. AWS AppSync

## Inputs
<a name="input-components"></a>

En raison du concept des types d'entrée et de sortie, certaines restrictions s'appliquent lors de la transmission d'arguments. Les types qui doivent généralement être transmis, en particulier les objets, sont restreints. Vous pouvez utiliser le type de saisie pour contourner cette règle. Les entrées sont des types contenant des scalaires, des énumérations et d'autres types d'entrées.

Les entrées sont définies à l'aide du `input` mot clé :

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}

input personInput { 
  id: ID!
  name: String
  age: Int
  occupation: occupationInput
}

input occupationInput {
  title: String
}
```

Comme vous pouvez le constater, nous pouvons avoir des entrées séparées qui imitent le type d'origine. Ces entrées seront souvent utilisées dans le cadre de vos opérations sur le terrain comme suit :

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}

input occupationInput {
  title: String
}

type Mutation {
  addPerson(id: ID!, name: String, age: Int, occupation: occupationInput): Person
}
```

Notez que nous sommes toujours en train de passer `occupationInput` à la place de `Occupation` pour créer un`Person`. 

Ce n'est qu'un des scénarios pour les entrées. Ils n'ont pas nécessairement besoin de copier les objets 1:1, et dans le code de production, vous ne les utiliserez probablement pas de cette manière. Il est recommandé de tirer parti des schémas GraphQL en définissant uniquement ce que vous devez saisir en tant qu'arguments.

De plus, les mêmes entrées peuvent être utilisées dans plusieurs opérations, mais nous vous déconseillons de le faire. Chaque opération doit idéalement contenir sa propre copie unique des entrées au cas où les exigences du schéma changeraient.

## Objets spéciaux
<a name="special-object-components"></a>

GraphQL réserve quelques mots clés à des objets spéciaux qui définissent une partie de la logique métier régissant la manière dont votre schéma affichera retrieve/manipulate les données. Il peut tout au plus y avoir un seul de ces mots clés dans un schéma. Ils servent de points d'entrée pour toutes les données demandées que vos clients exécutent avec votre service GraphQL. 

Les objets spéciaux sont également définis à l'aide du `type` mot-clé. Bien qu'ils soient utilisés différemment des types d'objets classiques, leur implémentation est très similaire.

------
#### [ Queries ]

Les requêtes sont très similaires aux `GET` opérations dans la mesure où elles effectuent une extraction en lecture seule pour obtenir des données de votre source. Dans GraphQL, `Query` définit tous les points d'entrée pour les clients effectuant des requêtes sur votre serveur. Il y en aura toujours un `Query` dans votre implémentation GraphQL.

Voici les types `Query` d'objets modifiés que nous avons utilisés dans notre précédent exemple de schéma :

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}
type Occupation {
  title: String
}
type Query {                                   
  people: [Person]
}
```

Notre `Query` contient un champ appelé `people` qui renvoie une liste d'`Person`instances à partir de la source de données. Supposons que nous devions modifier le comportement de notre application et que nous devions maintenant renvoyer une liste contenant uniquement les `Occupation` instances dans un but distinct. Nous pourrions simplement l'ajouter à la requête :

```
type Query {                                   
  people: [Person]
  occupations: [Occupation]
}
```

Dans GraphQL, nous pouvons traiter notre requête comme une source unique de requêtes. Comme vous pouvez le constater, cela est potentiellement beaucoup plus simple que RESTful les implémentations qui peuvent utiliser différents points de terminaison pour obtenir la même chose (`.../api/1/people`et`.../api/1/occupations`).

En supposant que nous ayons une implémentation de résolveur pour cette requête, nous pouvons maintenant effectuer une requête réelle. Tant que le `Query` type existe, nous devons l'appeler explicitement pour qu'il s'exécute dans le code de l'application. Cela peut être fait en utilisant le `query` mot clé :

```
query getItems {
   people {
      name
   }
   occupations {
      title
   }
}
```

Comme vous pouvez le voir, cette requête est appelée `getItems` et renvoie `people` (une liste d'`Person`objets) et `occupations` (une liste d'`Occupation`objets). Dans`people`, nous renvoyons uniquement le `name` champ de chacun`Person`, tandis que nous renvoyons le `title` champ de chacun`Occupation`. La réponse peut ressembler à ceci :

```
{
  "data": {
    "people": [
      {
        "name": "John Smith"
      },
      {
        "name": "Andrew Miller"
      },
      .
      .
      .
    ],
    "occupations": [
      {
        "title": "Firefighter"
      },
      {
        "title": "Bookkeeper"
      },
      .
      .
      .
    ]
  }
}
```

L'exemple de réponse montre comment les données suivent la forme de la requête. Chaque entrée récupérée est répertoriée dans le champ d'application du champ. `people`et `occupations` renvoient les éléments sous forme de listes séparées. Bien que cela soit utile, il peut être plus pratique de modifier la requête pour renvoyer une liste des noms et professions des personnes :

```
query getItems {
   people {
      name   
      occupation {
        title
      }
}
```

Il s'agit d'une modification légale car notre `Person` type contient un `occupation` champ de type`Occupation`. Une fois répertorié dans le champ de portée de`people`, nous `Person` renvoyons chacun `name` avec le nom associé `Occupation` à`title`. La réponse peut ressembler à ceci :

```
}
  "data": {
    "people": [
      {
        "name": "John Smith",
        "occupation": {
          "title": "Firefighter"
        }
      },
      {
        "name": "Andrew Miller",
        "occupation": {
          "title": "Bookkeeper"
        }
      },
      .
      .
      .
    ]
  }
}
```

------
#### [ Mutations ]

Les mutations sont similaires aux opérations de changement d'état telles que `PUT` ou`POST`. Ils exécutent une opération d'écriture pour modifier les données de la source, puis récupèrent la réponse. Ils définissent vos points d'entrée pour les demandes de modification de données. Contrairement aux requêtes, une mutation peut être incluse ou non dans le schéma en fonction des besoins du projet. Voici la mutation tirée de l'exemple de schéma :

```
type Mutation {
  addPerson(id: ID!, name: String, age: Int): Person
}
```

Le `addPerson` champ représente un point d'entrée qui ajoute un `Person` à la source de données. `addPerson`est le nom du champ ;`id`,`name`, et `age` sont les paramètres ; et `Person` est le type de retour. Rétrospectivement, le `Person` type :

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}
```

Nous avons ajouté le `occupation` champ. Cependant, nous ne pouvons pas définir ce champ sur `Occupation` directement car les objets ne peuvent pas être transmis en tant qu'arguments ; il s'agit uniquement de types de sortie. Nous devrions plutôt transmettre une entrée avec les mêmes champs en tant qu'argument :

```
input occupationInput {
  title: String
}
```

 Nous pouvons également facilement mettre à jour notre `addPerson` pour l'inclure en tant que paramètre lors de la création de nouvelles `Person` instances :

```
type Mutation {
  addPerson(id: ID!, name: String, age: Int, occupation: occupationInput): Person
}
```

Voici le schéma mis à jour :

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}

input occupationInput {
  title: String
}

type Mutation {
  addPerson(id: ID!, name: String, age: Int, occupation: occupationInput): Person
}
```

Notez que le `title` champ `occupation` sera transmis `occupationInput` pour terminer la création de l'objet au `Person` lieu de l'`Occupation`objet d'origine. En supposant que nous ayons une implémentation de résolveur pour`addPerson`, nous pouvons maintenant effectuer une véritable mutation. Tant que le `Mutation` type existe, nous devons l'appeler explicitement pour qu'il s'exécute dans le code de l'application. Cela peut être fait en utilisant le `mutation` mot clé :

```
mutation createPerson {
  addPerson(id: ID!, name: String, age: Int, occupation: occupationInput) {
    name
    age
    occupation {
      title
    }
  }
}
```

Cette mutation est appelée`createPerson`, et `addPerson` c'est l'opération. Pour en créer un nouveau`Person`, nous pouvons saisir les arguments pour `id``name`,`age`, et`occupation`. Dans le cadre de`addPerson`, nous pouvons également voir d'autres domaines tels que `name``age`, etc. Voici votre réponse ; ce sont les champs qui seront renvoyés une fois l'`addPerson`opération terminée. Voici la dernière partie de l'exemple :

```
mutation createPerson {
  addPerson(id: "1", name: "Steve Powers", age: "50", occupation: "Miner") {
    id
    name
    age
    occupation {
      title
    }
  }
}
```

En utilisant cette mutation, le résultat pourrait ressembler à ceci :

```
{
  "data": {
    "addPerson": {
      "id": "1",
      "name": "Steve Powers",
      "age": "50",
      "occupation": {
        "title": "Miner"
      }
    }
  }
}
```

Comme vous pouvez le constater, la réponse a renvoyé les valeurs que nous avions demandées dans le même format que celui défini dans notre mutation. Il est recommandé de renvoyer toutes les valeurs modifiées afin de réduire la confusion et d'éviter d'avoir à effectuer d'autres requêtes à l'avenir. Les mutations vous permettent d'inclure plusieurs opérations dans son champ d'application. Ils seront exécutés séquentiellement dans l'ordre indiqué dans la mutation. Par exemple, si nous créons une autre opération appelée `addOccupation` qui ajoute des titres de poste à la source de données, nous pouvons l'appeler dans la mutation suivante`addPerson`. `addPerson`sera traité en premier, suivi de`addOccupation`.

------
#### [ Subscriptions ]

Les abonnements [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications)permettent d'établir une connexion bidirectionnelle durable entre le serveur et ses clients. Généralement, un client s'abonne ou écoute le serveur. Chaque fois que le serveur effectue une modification côté serveur ou exécute un événement, le client abonné reçoit les mises à jour. Ce type de protocole est utile lorsque plusieurs clients sont abonnés et doivent être informés des modifications apportées au serveur ou à d'autres clients. Par exemple, les abonnements peuvent être utilisés pour mettre à jour les flux de réseaux sociaux. Il peut y avoir deux utilisateurs, l'utilisateur A et l'utilisateur B, qui sont tous deux abonnés aux mises à jour automatiques des notifications chaque fois qu'ils reçoivent des messages directs. L'utilisateur A sur le client A pourrait envoyer un message direct à l'utilisateur B sur le client B. Le client de l'utilisateur A enverrait le message direct, qui serait traité par le serveur. Le serveur enverrait ensuite le message direct au compte de l'utilisateur B tout en envoyant une notification automatique au client B.

Voici un exemple `Subscription` que nous pourrions ajouter à l'exemple de schéma :

```
type Subscription {                                   
  personAdded: Person
}
```

Le `personAdded` champ envoie un message aux clients abonnés chaque fois qu'un nouveau message `Person` est ajouté à la source de données. En supposant que nous ayons une implémentation de résolveur pour`personAdded`, nous pouvons désormais utiliser l'abonnement. Tant que le `Subscription` type existe, nous devons l'appeler explicitement pour qu'il s'exécute dans le code de l'application. Cela peut être fait en utilisant le `subscription` mot clé :

```
subscription personAddedOperation {
  personAdded {
    id
    name
  }
}
```

L'abonnement est appelé`personAddedOperation`, et l'opération l'est`personAdded`. `personAdded`renverra les `name` champs `id` et des nouvelles `Person` instances. En regardant l'exemple de mutation, nous avons ajouté une `Person` en utilisant cette opération :

```
addPerson(id: "1", name: "Steve Powers", age: "50", occupation: "Miner")
```

Si nos clients étaient abonnés aux mises à jour des nouvelles versions`Person`, ils pourraient voir ceci après les `addPerson` essais :

```
{
  "data": {
    "personAdded": {
      "id": "1",
      "name": "Steve Powers"
    }
  }
}
```

Vous trouverez ci-dessous un résumé de ce que proposent les abonnements :

Les abonnements sont des canaux bidirectionnels qui permettent au client et au serveur de recevoir des mises à jour rapides mais régulières. Ils utilisent généralement le WebSocket protocole, qui crée des connexions standardisées et sécurisées.

Les abonnements sont souples dans la mesure où ils réduisent les frais de configuration des connexions. Une fois abonné, un client peut simplement continuer à utiliser cet abonnement pendant de longues périodes. Ils utilisent généralement les ressources informatiques de manière efficace en permettant aux développeurs d'adapter la durée de vie de l'abonnement et de configurer les informations qui seront demandées.

En général, les abonnements permettent au client de souscrire plusieurs abonnements à la fois. En ce qui concerne AWS AppSync, les abonnements ne sont utilisés que pour recevoir des mises à jour en temps réel du AWS AppSync service. Ils ne peuvent pas être utilisés pour effectuer des requêtes ou des mutations.

La principale alternative aux abonnements est le sondage, qui envoie des requêtes à intervalles réguliers pour demander des données. Ce processus est généralement moins efficace que les abonnements et met beaucoup de pression à la fois sur le client et sur le backend.

------

Une chose qui n'a pas été mentionnée dans notre exemple de schéma est le fait que vos types d'objets spéciaux doivent également être définis dans une `schema` racine. Ainsi, lorsque vous exportez un schéma au AWS AppSync format, il peut ressembler à ceci :

------
#### [ schema.graphql ]

```
schema {
  query: Query
  mutation: Mutation
  subscription: Subscription
}

.
.
.

type Query {                                   
  # code goes here
}
type Mutation {                                   
  # code goes here
}
type Subscription {                                   
  # code goes here
}
```

------

## Énumération
<a name="enum-components"></a>

Les énumérations, ou énumérations, sont des scalaires spéciaux qui limitent les arguments juridiques qu'un type ou un champ peut avoir. Cela signifie que chaque fois qu'une énumération est définie dans le schéma, son type ou champ associé sera limité aux valeurs de l'énumération. Les énumérations sont sérialisées sous forme de scalaires de chaînes. Notez que différents langages de programmation peuvent gérer les énumérations GraphQL différemment. Par exemple, n' JavaScript a pas de support d'énumération natif, de sorte que les valeurs d'énumération peuvent être mappées à des valeurs int à la place.

Les énumérations sont définies à l'aide du `enum` mot-clé. Voici un exemple :

```
enum trafficSignals {
  solidRed
  solidYellow
  solidGreen
  greenArrowLeft
  ...
}
```

Lors de l'appel de l'`trafficLights`énumération, le ou les arguments ne peuvent être que `solidRed``solidYellow`,`solidGreen`, etc. Il est courant d'utiliser des énumérations pour décrire des éléments qui offrent un nombre de choix distinct mais limité.

## Unions/Interfaces
<a name="union-interface-components"></a>

Voir [Interfaces et unions](https://docs.aws.amazon.com/appsync/latest/devguide/interfaces-and-unions.html) dans GraphQL.

# Champs GraphQL
<a name="graphql-fields"></a>

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. Par exemple, voici un type d'`Person`objet :

```
type Person {                                  
   name: String                                  
   age: Int
}
```

Dans ce cas, les champs sont `name` `age` et contiennent respectivement une `Int` valeur `String` et. Les champs d'objet tels que ceux présentés ci-dessus peuvent être utilisés comme entrées dans les champs (opérations) de vos requêtes et mutations. Par exemple, consultez ce qui `Query` suit :

```
type Query {                                   
  people: [Person]
}
```

Le `people` champ demande toutes les instances de `Person` depuis la source de données. Lorsque vous ajoutez ou extrayez un fichier `Person` dans votre serveur GraphQL, vous pouvez vous attendre à ce que les données suivent le format de vos types et de vos champs, c'est-à-dire que la structure de vos données dans le schéma détermine la manière dont elles seront structurées dans votre réponse :

```
}
  "data": {
    "people": [
      {
        "name": "John Smith",
        "age": "50"
      },
      {
        "name": "Andrew Miller",
        "age": "60"
      },
      .
      .
      .
    ]
  }
}
```

Les champs jouent un rôle important dans la structuration des données. Quelques propriétés supplémentaires expliquées ci-dessous peuvent être appliquées aux champs pour une personnalisation accrue.

## Lists
<a name="list-components"></a>

Les listes renvoient tous les éléments d'un type spécifié. Une liste peut être ajoutée au type d'un champ à l'aide de crochets `[]` : 

```
type Person { 
  name: String
  age: Int
}
type Query {                                   
  people: [Person]
}
```

Dans`Query`, les crochets qui l'entourent `Person` indiquent que vous souhaitez renvoyer toutes les instances `Person` de la source de données sous forme de tableau. Dans la réponse, les `age` valeurs `name` et de chacune `Person` seront renvoyées sous forme de liste unique et délimitée :

```
}
  "data": {
    "people": [
      {
        "name": "John Smith",         # Data of Person 1
        "age": "50"
      },
      {
        "name": "Andrew Miller",      # Data of Person 2
        "age": "60"
      },
      .                               # Data of Person N
      .
      .
    ]
  }
}
```

Vous n'êtes pas limité aux types d'objets spéciaux. Vous pouvez également utiliser des listes dans les champs des types d'objets classiques.

## Non nuls
<a name="non-null-components"></a>

Les valeurs non nulles indiquent un champ qui ne peut pas être nul dans la réponse. Vous pouvez attribuer à un champ une valeur non nulle en utilisant le `!` symbole :

```
type Person { 
  name: String!
  age: Int
}
type Query {                                   
  people: [Person]
}
```

Le `name` champ ne peut pas être explicitement nul. Si vous interrogiez la source de données et que vous fournissiez une entrée nulle pour ce champ, une erreur serait générée.

Vous pouvez combiner des listes et des valeurs non nulles. Comparez les requêtes suivantes :

```
type Query {                                   
  people: [Person!]      # Use case 1
}

.
.
.

type Query {                                   
  people: [Person]!      # Use case 2
}

.
.
.

type Query {                                   
  people: [Person!]!     # Use case 3
}
```

Dans le cas d'utilisation 1, la liste ne peut pas contenir d'éléments nuls. Dans le cas d'utilisation 2, la liste elle-même ne peut pas être définie sur null. Dans le cas d'utilisation 3, la liste et ses éléments ne peuvent pas être nuls. Cependant, dans tous les cas, vous pouvez toujours renvoyer des listes vides.

Comme vous pouvez le constater, GraphQL comporte de nombreux composants mobiles. Dans cette section, nous avons présenté la structure d'un schéma simple ainsi que les différents types et champs qu'un schéma prend en charge. Dans la section suivante, vous découvrirez les autres composants d'une API GraphQL et leur fonctionnement avec le schéma.