

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.

# Utilisation des opérations par lots DynamoDB dans AWS AppSync
<a name="tutorial-dynamodb-batch-js"></a>

AWS AppSync prend en charge l'utilisation des opérations par lots Amazon DynamoDB sur une ou plusieurs tables d'une même région. Les opérations prises en charge sont `BatchGetItem`, `BatchPutItem` et `BatchDeleteItem`. En utilisant ces fonctionnalités dans AWS AppSync, vous pouvez effectuer des tâches telles que :
+ Transmission d'une liste de clés en une seule requête et renvoi des résultats à partir d'une table
+ Lecture d'enregistrements d'une ou de plusieurs tables en une seule requête
+ Écrire des enregistrements en bloc dans une ou plusieurs tables
+ Écrire ou supprimer de manière conditionnelle des enregistrements dans plusieurs tables susceptibles d'avoir une relation

Les opérations par lots AWS AppSync présentent deux différences principales par rapport aux opérations non groupées :
+ Le rôle de source de données doit disposer d'autorisations sur toutes les tables auxquelles le résolveur aura accès.
+ La spécification de table pour un résolveur fait partie de l'objet de demande.

## Lots à table unique
<a name="single-table-batch-js"></a>

**Avertissement**  
`BatchPutItem`et ne `BatchDeleteItem` sont pas pris en charge lorsqu'ils sont utilisés avec la détection et la résolution de conflits. Ces paramètres doivent être désactivés pour éviter d'éventuelles erreurs.

Pour commencer, créons une nouvelle API GraphQL. Dans la AWS AppSync console, choisissez **Create API** APIs, **GraphQL** et **Design from scratch**. **Nommez votre API`BatchTutorial API`, choisissez **Next**, puis à l'étape **Spécifier les ressources GraphQL**, choisissez Create **GraphQL resources later, puis** cliquez sur Next.** Vérifiez vos informations et créez l'API. Accédez à la page **Schéma** et collez le schéma suivant, en notant que pour la requête, nous allons transmettre une liste de IDs :

```
type Post {
    id: ID!
    title: String
}

input PostInput {
    id: ID!
    title: String
}

type Query {
    batchGet(ids: [ID]): [Post]
}

type Mutation {
    batchAdd(posts: [PostInput]): [Post]
    batchDelete(ids: [ID]): [Post]
}
```

Enregistrez votre schéma et choisissez **Create Resources** en haut de la page. Choisissez **Utiliser le type existant**, puis sélectionnez le `Post` type. Donnez un nom à votre table`Posts`. **Assurez-vous que la **clé primaire** est définie sur`id`, désélectionnez **Générer automatiquement GraphQL** (vous fournirez votre propre code), puis sélectionnez Créer.** Pour commencer, AWS AppSync crée une nouvelle table DynamoDB et une source de données connectée à la table avec les rôles appropriés. Cependant, vous devez encore ajouter quelques autorisations au rôle. Accédez à la page **Sources de données** et choisissez la nouvelle source de données. Sous **Sélectionnez un rôle existant**, vous remarquerez qu'un rôle a été automatiquement créé pour le tableau. Prenez note du rôle (qui devrait ressembler à quelque chose comme ça`appsync-ds-ddb-aaabbbcccddd-Posts`), puis accédez à la console IAM ([https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/)). Dans la console IAM, choisissez **Rôles**, puis choisissez votre rôle dans le tableau. Dans votre rôle, sous **Politiques d'autorisations**, cliquez sur le bouton `+` « » à côté de la politique (le nom doit être similaire au nom du rôle). Choisissez **Modifier** en haut du pliable lorsque la politique apparaît. Vous devez ajouter des autorisations par lots à votre politique, en particulier `dynamodb:BatchGetItem` et`dynamodb:BatchWriteItem`. Cela ressemblera à ceci :

------
#### [ JSON ]

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:DeleteItem",
                "dynamodb:GetItem",
                "dynamodb:PutItem",
                "dynamodb:Query",
                "dynamodb:Scan",
                "dynamodb:UpdateItem",
                "dynamodb:BatchWriteItem",
                "dynamodb:BatchGetItem"
            ],
            "Resource": [
                "arn:aws:dynamodb:us-east-1:111122223333:table/locationReadings",
                "arn:aws:dynamodb:us-east-1:111122223333:table/locationReadings/*",
                "arn:aws:dynamodb:us-east-1:111122223333:table/temperatureReadings",
                "arn:aws:dynamodb:us-east-1:111122223333:table/temperatureReadings/*"
            ]
        }
    ]
}
```

------

Choisissez **Suivant**, puis **Enregistrer les modifications**. Votre politique devrait autoriser le traitement par lots dès maintenant.

De retour dans la AWS AppSync console, accédez à la page **Schéma** et sélectionnez **Joindre** à côté du `Mutation.batchAdd` champ. Créez votre résolveur en utilisant le `Posts` tableau comme source de données. Dans l'éditeur de code, remplacez les gestionnaires par l'extrait ci-dessous. Cet extrait prend automatiquement chaque élément du `input PostInput` type GraphQL et crée une carte, nécessaire à l'opération : `BatchPutItem`

```
import { util } from "@aws-appsync/utils";

export function request(ctx) {
  return {
    operation: "BatchPutItem",
    tables: {
      Posts: ctx.args.posts.map((post) => util.dynamodb.toMapValues(post)),
    },
  };
}

export function response(ctx) {
  if (ctx.error) {
    util.error(ctx.error.message, ctx.error.type);
  }
  return ctx.result.data.Posts;
}
```

Accédez à la page **Requêtes** de la AWS AppSync console et exécutez la `batchAdd` mutation suivante :

```
mutation add {
    batchAdd(posts:[{
            id: 1 title: "Running in the Park"},{
            id: 2 title: "Playing fetch"
        }]){
            id
            title
    }
}
```

Vous devriez voir les résultats imprimés à l'écran ; cela peut être validé en consultant la console DynamoDB pour rechercher les valeurs écrites dans la table. `Posts`

Ensuite, répétez le processus consistant à joindre un résolveur, sauf pour le `Query.batchGet` champ utilisant la `Posts` table comme source de données. Remplacez les gestionnaires par le code ci-dessous. Ce processus prend automatiquement chaque élément du type GraphQL `ids:[]` et crée une mappe, qui est nécessaire pour l'opération `BatchGetItem` :

```
import { util } from "@aws-appsync/utils";

export function request(ctx) {
  return {
    operation: "BatchGetItem",
    tables: {
      Posts: {
        keys: ctx.args.ids.map((id) => util.dynamodb.toMapValues({ id })),
        consistentRead: true,
      },
    },
  };
}

export function response(ctx) {
  if (ctx.error) {
    util.error(ctx.error.message, ctx.error.type);
  }
  return ctx.result.data.Posts;
}
```

Retournez maintenant à la page **Requêtes** de la AWS AppSync console et exécutez la `batchGet` requête suivante :

```
query get {
    batchGet(ids:[1,2,3]){
        id
        title
    }
}
```

Vous devez obtenir les résultats des deux valeurs `id` que vous avez ajoutées précédemment. Notez qu'une `null` valeur a été renvoyée pour le `id` avec une valeur de`3`. Cela est dû au fait qu'il n'y avait pas encore d'enregistrement dans votre `Posts` table contenant cette valeur. Notez également que cela AWS AppSync renvoie les résultats dans le même ordre que les clés transmises à la requête, ce qui constitue une fonctionnalité supplémentaire qui AWS AppSync fonctionne en votre nom. Donc, si vous passez à`batchGet(ids:[1,3,2])`, vous verrez que la commande a changé. Vous saurez également quel `id` a renvoyé une valeur `null`.

Enfin, attachez un autre résolveur au `Mutation.batchDelete` champ en utilisant la `Posts` table comme source de données. Remplacez les gestionnaires par le code ci-dessous. Ce processus prend automatiquement chaque élément du type GraphQL `ids:[]` et crée une mappe, qui est nécessaire pour l'opération `BatchGetItem` :

```
import { util } from "@aws-appsync/utils";

export function request(ctx) {
  return {
    operation: "BatchDeleteItem",
    tables: {
      Posts: ctx.args.ids.map((id) => util.dynamodb.toMapValues({ id })),
    },
  };
}

export function response(ctx) {
  if (ctx.error) {
    util.error(ctx.error.message, ctx.error.type);
  }
  return ctx.result.data.Posts;
}
```

Retournez maintenant à la page **Requêtes** de la AWS AppSync console et exécutez la `batchDelete` mutation suivante :

```
mutation delete {
    batchDelete(ids:[1,2]){ id }
}
```

Les enregistrements contenant les `id` `1` et `2` doivent désormais avoir été supprimés. Si vous exécutez à nouveau la requête `batchGet()` à partir de l'état précédent, le résultat renvoyé devrait être `null`.

## Lot multi-tables
<a name="multi-table-batch-js"></a>

**Avertissement**  
`BatchPutItem`et ne `BatchDeleteItem` sont pas pris en charge lorsqu'ils sont utilisés avec la détection et la résolution de conflits. Ces paramètres doivent être désactivés pour éviter d'éventuelles erreurs.

AWS AppSync vous permet également d'effectuer des opérations par lots sur plusieurs tables. Créons un application plus complexe. Imaginez que nous sommes en train de créer une application de santé pour animaux de compagnie dans laquelle des capteurs signalent l'emplacement et la température corporelle de l'animal. Les capteurs sont alimentés par piles et tentent de se connecter au réseau toutes les deux ou trois minutes. Lorsqu'un capteur établit une connexion, il envoie ses relevés à notre AWS AppSync API. Des déclencheurs analysent alors les données afin de pouvoir transmettre un tableau de bord au propriétaire de l'animal. Concentrons-nous sur la représentation des interactions entre le capteur et le magasin de données backend.

Dans la AWS AppSync console, choisissez **Create API** APIs, **GraphQL** et **Design from scratch**. **Nommez votre API`MultiBatchTutorial API`, choisissez **Next**, puis à l'étape **Spécifier les ressources GraphQL**, choisissez Create **GraphQL resources later, puis** cliquez sur Next.** Vérifiez vos informations et créez l'API. Accédez à la page **Schéma**, collez et enregistrez le schéma suivant :

```
type Mutation {
    # Register a batch of readings
    recordReadings(tempReadings: [TemperatureReadingInput], locReadings: [LocationReadingInput]): RecordResult
    # Delete a batch of readings
    deleteReadings(tempReadings: [TemperatureReadingInput], locReadings: [LocationReadingInput]): RecordResult
}

type Query {
    # Retrieve all possible readings recorded by a sensor at a specific time
    getReadings(sensorId: ID!, timestamp: String!): [SensorReading]
}

type RecordResult {
    temperatureReadings: [TemperatureReading]
    locationReadings: [LocationReading]
}

interface SensorReading {
    sensorId: ID!
    timestamp: String!
}

# Sensor reading representing the sensor temperature (in Fahrenheit)
type TemperatureReading implements SensorReading {
    sensorId: ID!
    timestamp: String!
    value: Float
}

# Sensor reading representing the sensor location (lat,long)
type LocationReading implements SensorReading {
    sensorId: ID!
    timestamp: String!
    lat: Float
    long: Float
}

input TemperatureReadingInput {
    sensorId: ID!
    timestamp: String
    value: Float
}

input LocationReadingInput {
    sensorId: ID!
    timestamp: String
    lat: Float
    long: Float
}
```

Nous devons créer deux tables DynamoDB :
+ `locationReadings`enregistrera les relevés de position du capteur.
+ `temperatureReadings`enregistrera les relevés de température du capteur.

Les deux tables partageront la même structure de clé primaire : `sensorId (String)` en tant que clé de partition et `timestamp (String)` en tant que clé de tri.

Choisissez **Créer des ressources** en haut de la page. Choisissez **Utiliser le type existant**, puis sélectionnez le `locationReadings` type. Donnez un nom à votre table`locationReadings`. Assurez-vous que la **clé primaire** est définie sur `sensorId` et que la clé de tri est définie sur`timestamp`. **Désélectionnez **Générer automatiquement GraphQL** (vous fournirez votre propre code), puis sélectionnez Créer.** Répétez ce processus pour `temperatureReadings` utiliser le `temperatureReadings` comme type et nom de table. Utilisez les mêmes touches que ci-dessus.

Vos nouvelles tables contiendront les rôles générés automatiquement. Vous devez encore ajouter quelques autorisations à ces rôles. Accédez à la page **Sources de données** et choisissez`locationReadings`. Sous **Sélectionner un rôle existant**, vous pouvez voir le rôle. Prenez note du rôle (qui devrait ressembler à quelque chose comme ça`appsync-ds-ddb-aaabbbcccddd-locationReadings`), puis accédez à la console IAM ([https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/)). Dans la console IAM, choisissez **Rôles**, puis choisissez votre rôle dans le tableau. Dans votre rôle, sous **Politiques d'autorisations**, cliquez sur le bouton `+` « » à côté de la politique (le nom doit être similaire au nom du rôle). Choisissez **Modifier** en haut du pliable lorsque la politique apparaît. Vous devez ajouter des autorisations à cette politique. Cela ressemblera à ceci :

Choisissez **Suivant**, puis **Enregistrer les modifications**. Répétez ce processus pour la source de `temperatureReadings` données en utilisant le même extrait de politique ci-dessus.

### BatchPutItem - Enregistrement des lectures des capteurs
<a name="batchputitem-recording-sensor-readings-js"></a>

Nos capteurs doivent être en mesure d'envoyer leurs relevés une fois qu'ils sont connectés à Internet. Le champ GraphQL `Mutation.recordReadings` est l'API qu'ils utilisent à cet effet. Nous devrons ajouter un résolveur à ce champ.

Sur la page **Schéma** de la AWS AppSync console, sélectionnez **Joindre** à côté du `Mutation.recordReadings` champ. Sur l'écran suivant, créez votre résolveur en utilisant le `locationReadings` tableau comme source de données.

Après avoir créé votre résolveur, remplacez les gestionnaires par le code suivant dans l'éditeur. Cette `BatchPutItem` opération nous permet de spécifier plusieurs tables : 

```
import { util } from '@aws-appsync/utils'

export function request(ctx) {
	const { locReadings, tempReadings } = ctx.args
	const locationReadings = locReadings.map((loc) => util.dynamodb.toMapValues(loc))
	const temperatureReadings = tempReadings.map((tmp) => util.dynamodb.toMapValues(tmp))

	return {
		operation: 'BatchPutItem',
		tables: {
			locationReadings,
			temperatureReadings,
		},
	}
}

export function response(ctx) {
	if (ctx.error) {
		util.appendError(ctx.error.message, ctx.error.type)
	}
	return ctx.result.data
}
```

Les opérations par lots peuvent renvoyer à la fois des erreurs et des résultats à la suite de l'appel. Dans ce cas, nous pouvons effectuer certaines opérations de traitement des erreurs supplémentaires.

**Note**  
L'utilisation de `utils.appendError()` est similaire à la`util.error()`, avec la principale différence qu'elle n'interrompt pas l'évaluation du gestionnaire de demandes ou de réponses. Il signale plutôt qu'une erreur s'est produite dans le champ, mais permet d'évaluer le gestionnaire et, par conséquent, de renvoyer les données à l'appelant. Nous vous recommandons de l'utiliser `utils.appendError()` lorsque votre application doit renvoyer des résultats partiels.

Enregistrez le résolveur et accédez à la page **Requêtes** de la AWS AppSync console. Nous pouvons maintenant envoyer des relevés de capteurs.

Exécutez la mutation suivante :

```
mutation sendReadings {
  recordReadings(
    tempReadings: [
      {sensorId: 1, value: 85.5, timestamp: "2018-02-01T17:21:05.000+08:00"},
      {sensorId: 1, value: 85.7, timestamp: "2018-02-01T17:21:06.000+08:00"},
      {sensorId: 1, value: 85.8, timestamp: "2018-02-01T17:21:07.000+08:00"},
      {sensorId: 1, value: 84.2, timestamp: "2018-02-01T17:21:08.000+08:00"},
      {sensorId: 1, value: 81.5, timestamp: "2018-02-01T17:21:09.000+08:00"}
    ]
    locReadings: [
      {sensorId: 1, lat: 47.615063, long: -122.333551, timestamp: "2018-02-01T17:21:05.000+08:00"},
      {sensorId: 1, lat: 47.615163, long: -122.333552, timestamp: "2018-02-01T17:21:06.000+08:00"},
      {sensorId: 1, lat: 47.615263, long: -122.333553, timestamp: "2018-02-01T17:21:07.000+08:00"},
      {sensorId: 1, lat: 47.615363, long: -122.333554, timestamp: "2018-02-01T17:21:08.000+08:00"},
      {sensorId: 1, lat: 47.615463, long: -122.333555, timestamp: "2018-02-01T17:21:09.000+08:00"}
    ]) {
    locationReadings {
      sensorId
      timestamp
      lat
      long
    }
    temperatureReadings {
      sensorId
      timestamp
      value
    }
  }
}
```

Nous avons envoyé dix relevés de capteurs pour une mutation, les résultats étant répartis sur deux tableaux. Utilisez la console DynamoDB pour vérifier que les données apparaissent à la fois dans les `locationReadings` tables et. `temperatureReadings`

### BatchDeleteItem - Suppression des relevés du capteur
<a name="batchdeleteitem-deleting-sensor-readings-js"></a>

De même, nous devrions également être en mesure de supprimer des lots de relevés de capteurs. Nous allons utiliser le champ GraphQL `Mutation.deleteReadings` à cet effet. Sur la page **Schéma** de la AWS AppSync console, sélectionnez **Joindre** à côté du `Mutation.deleteReadings` champ. Sur l'écran suivant, créez votre résolveur en utilisant le `locationReadings` tableau comme source de données.

Après avoir créé votre résolveur, remplacez les gestionnaires de l'éditeur de code par l'extrait ci-dessous. Dans ce résolveur, nous utilisons un mappeur de fonctions auxiliaires qui extrait le `sensorId` et `timestamp` à partir des entrées fournies. 

```
import { util } from '@aws-appsync/utils'

export function request(ctx) {
	const { locReadings, tempReadings } = ctx.args
	const mapper = ({ sensorId, timestamp }) => util.dynamodb.toMapValues({ sensorId, timestamp })

	return {
		operation: 'BatchDeleteItem',
		tables: {
			locationReadings: locReadings.map(mapper),
			temperatureReadings: tempReadings.map(mapper),
		},
	}
}

export function response(ctx) {
	if (ctx.error) {
		util.appendError(ctx.error.message, ctx.error.type)
	}
	return ctx.result.data
}
```

Enregistrez le résolveur et accédez à la page **Requêtes** de la AWS AppSync console. Supprimons maintenant quelques mesures du capteur.

Exécutez la mutation suivante :

```
mutation deleteReadings {
  # Let's delete the first two readings we recorded
  deleteReadings(
    tempReadings: [{sensorId: 1, timestamp: "2018-02-01T17:21:05.000+08:00"}]
    locReadings: [{sensorId: 1, timestamp: "2018-02-01T17:21:05.000+08:00"}]) {
    locationReadings {
      sensorId
      timestamp
      lat
      long
    }
    temperatureReadings {
      sensorId
      timestamp
      value
    }
  }
}
```

**Note**  
Contrairement à l'opération `DeleteItem`, l'élément complètement supprimé n'est pas renvoyé dans la réponse. Seule la clé passée est renvoyée. Pour en savoir plus, consultez la [référence de la fonction BatchDeleteItem in JavaScript resolver pour DynamoDB](https://docs.aws.amazon.com/appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-batch-delete-item).

Vérifiez via la console DynamoDB que ces deux lectures ont été supprimées `locationReadings` des tables et. `temperatureReadings`

### BatchGetItem - Récupérez les lectures
<a name="batchgetitem-retrieve-readings-js"></a>

Une autre opération courante de notre application consiste à récupérer les mesures d'un capteur à un moment précis. Nous allons joindre un résolveur au champ GraphQL `Query.getReadings` dans notre schéma. Sur la page **Schéma** de la AWS AppSync console, sélectionnez **Joindre** à côté du `Query.getReadings` champ. Sur l'écran suivant, créez votre résolveur en utilisant le `locationReadings` tableau comme source de données.

Utilisons le code suivant : 

```
import { util } from '@aws-appsync/utils'

export function request(ctx) {
	const keys = [util.dynamodb.toMapValues(ctx.args)]
	const consistentRead = true
	return {
		operation: 'BatchGetItem',
		tables: {
			locationReadings: { keys, consistentRead },
			temperatureReadings: { keys, consistentRead },
		},
	}
}

export function response(ctx) {
	if (ctx.error) {
		util.appendError(ctx.error.message, ctx.error.type)
	}
	const { locationReadings: locs, temperatureReadings: temps } = ctx.result.data

	return [
		...locs.map((l) => ({ ...l, __typename: 'LocationReading' })),
		...temps.map((t) => ({ ...t, __typename: 'TemperatureReading' })),
	]
}
```

Enregistrez le résolveur et accédez à la page **Requêtes** de la AWS AppSync console. Maintenant, récupérons les relevés de nos capteurs.

Exécutez la requête suivante :

```
query getReadingsForSensorAndTime {
  # Let's retrieve the very first two readings
  getReadings(sensorId: 1, timestamp: "2018-02-01T17:21:06.000+08:00") {
    sensorId
    timestamp
    ...on TemperatureReading {
      value
    }
    ...on LocationReading {
      lat
      long
    }
  }
}
```

Nous avons démontré avec succès l'utilisation des opérations par lots DynamoDB à l'aide de. AWS AppSync

## Gestion des erreurs
<a name="error-handling-js"></a>

Dans AWS AppSync, les opérations de source de données peuvent parfois renvoyer des résultats partiels. Le terme résultats partiels est le terme que nous allons utiliser pour désigner une sortie d'opération composée de données et d'une erreur. La gestion des erreurs étant intrinsèquement spécifique à l'application, AWS AppSync vous avez la possibilité de gérer les erreurs dans le gestionnaire de réponses. L'erreur d'appel du résolveur, le cas échéant, est disponible depuis le contexte sous la forme `ctx.error`. Les erreurs d'appel incluent toujours un message et un type, accessibles sous la forme des propriétés `ctx.error.message` et `ctx.error.type`. Dans le gestionnaire de réponses, vous pouvez gérer les résultats partiels de trois manières :

1. Avalez l'erreur d'invocation en renvoyant simplement des données.

1. Déclenchez une erreur (en utilisant`util.error(...)`) en arrêtant l'évaluation du gestionnaire, qui ne renverra aucune donnée.

1. Ajoutez une erreur (en utilisant`util.appendError(...)`) et renvoyez également des données.

Démontrons chacun des trois points ci-dessus avec les opérations par lots DynamoDB.

### Opérations par lots DynamoDB
<a name="dynamodb-batch-operations-js"></a>

Dans le cas des opérations par lots DynamoDB, il est possible qu'un lot ne soit exécuté que partiellement. En d'autres termes, il est possible que certains des éléments ou des clés demandés ne soient pas traités. S'il n' AWS AppSync est pas possible de terminer un lot, les éléments non traités et une erreur d'invocation seront définis dans le contexte.

Nous allons mettre en œuvre la gestion des erreurs à l'aide de la configuration de champ `Query.getReadings` de l'opération `BatchGetItem` provenant de la section précédente de ce didacticiel. Cette fois, nous allons supposer que, lors de l'exécution du champ `Query.getReadings`, la table DynamoDB `temperatureReadings` a dépassé le débit alloué. DynamoDB a déclenché `ProvisionedThroughputExceededException` un lors de la deuxième tentative pour traiter AWS AppSync les éléments restants du lot.

Le JSON suivant représente le contexte sérialisé après l'appel par lots DynamoDB mais avant l'appel du gestionnaire de réponses :

```
{
  "arguments": {
    "sensorId": "1",
    "timestamp": "2018-02-01T17:21:05.000+08:00"
  },
  "source": null,
  "result": {
    "data": {
      "temperatureReadings": [
        null
      ],
      "locationReadings": [
        {
          "lat": 47.615063,
          "long": -122.333551,
          "sensorId": "1",
          "timestamp": "2018-02-01T17:21:05.000+08:00"
        }
      ]
    },
    "unprocessedKeys": {
      "temperatureReadings": [
        {
          "sensorId": "1",
          "timestamp": "2018-02-01T17:21:05.000+08:00"
        }
      ],
      "locationReadings": []
    }
  },
  "error": {
    "type": "DynamoDB:ProvisionedThroughputExceededException",
    "message": "You exceeded your maximum allowed provisioned throughput for a table or for one or more global secondary indexes. (...)"
  },
  "outErrors": []
}
```

Quelques points à noter concernant le contexte :
+ L'erreur d'invocation a été définie sur le contexte et AWS AppSync le type d'erreur a été défini sur. `ctx.error` `DynamoDB:ProvisionedThroughputExceededException`
+ Les résultats sont mappés par table ci-dessous `ctx.result.data` même en cas d'erreur.
+ Les clés non traitées sont disponibles sur`ctx.result.data.unprocessedKeys`. Ici, AWS AppSync impossible de récupérer l'élément avec la clé (SensorID:1, Timestamp:2018-02-01T 17:21:05.000 \$1 08:00) en raison d'un débit de table insuffisant.

**Note**  
Pour `BatchPutItem`, la valeur est `ctx.result.data.unprocessedItems`. Pour `BatchDeleteItem`, la valeur est `ctx.result.data.unprocessedKeys`.

Nous allons traiter cette erreur de trois façons différentes.

#### 1. Digestion de l'erreur d'appel
<a name="swallowing-the-invocation-error-js"></a>

Le renvoi des données sans gestion de l'erreur d'appel se traduit par une digestion de l'erreur, ce qui permet au résultat du champ GraphQL donné d'être toujours réussi.

Le code que nous écrivons est familier et se concentre uniquement sur les données de résultat.

**Gestionnaire de réponses**

```
export function response(ctx) {
  return ctx.result.data
}
```

**Réponse GraphQL**

```
{
  "data": {
    "getReadings": [
      {
        "sensorId": "1",
        "timestamp": "2018-02-01T17:21:05.000+08:00",
        "lat": 47.615063,
        "long": -122.333551
      },
      {
        "sensorId": "1",
        "timestamp": "2018-02-01T17:21:05.000+08:00",
        "value": 85.5
      }
    ]
  }
}
```

Aucune erreur n'est ajoutée à la réponse d'erreur car l'action n'a porté que sur les données.

#### 2. Génération d'une erreur pour annuler l'exécution du gestionnaire de réponses
<a name="raising-an-error-to-abort-the-response-execution-js"></a>

Lorsque les échecs partiels doivent être traités comme des échecs complets du point de vue du client, vous pouvez interrompre l'exécution du gestionnaire de réponses pour empêcher le renvoi de données. La méthode d'utilitaire `util.error(...)` permet d'obtenir exactement ce comportement.

**Code du gestionnaire de réponses**

```
export function response(ctx) {
  if (ctx.error) {
    util.error(ctx.error.message, ctx.error.type, null, ctx.result.data.unprocessedKeys);
  }
  return ctx.result.data;
}
```

**Réponse GraphQL**

```
{
  "data": {
    "getReadings": null
  },
  "errors": [
    {
      "path": [
        "getReadings"
      ],
      "data": null,
      "errorType": "DynamoDB:ProvisionedThroughputExceededException",
      "errorInfo": {
        "temperatureReadings": [
          {
            "sensorId": "1",
            "timestamp": "2018-02-01T17:21:05.000+08:00"
          }
        ],
        "locationReadings": []
      },
      "locations": [
        {
          "line": 58,
          "column": 3
        }
      ],
      "message": "You exceeded your maximum allowed provisioned throughput for a table or for one or more global secondary indexes. (...)"
    }
  ]
}
```

Même si certains résultats peuvent avoir été renvoyés par l'opération de traitement par lots DynamoDB, nous avons choisi de déclencher une erreur se traduisant par une valeur null pour le champ GraphQL `getReadings` et l'erreur a été ajoutée au bloc d'*erreurs* de la réponse GraphQL.

#### 3. Ajout d'une erreur pour renvoyer à la fois les données et les erreurs
<a name="appending-an-error-to-return-both-data-and-errors-js"></a>

Dans certains cas, afin d'offrir une meilleure expérience utilisateur, les applications peuvent renvoyer des résultats partiels et informer leurs clients des éléments non traités. Les clients peuvent choisir d'implémenter une nouvelle tentative ou de renvoyer l'erreur à l'utilisateur final. `util.appendError(...)`Il s'agit de la méthode utilitaire qui permet ce comportement en permettant au concepteur de l'application d'ajouter des erreurs au contexte sans interférer avec l'évaluation du gestionnaire de réponses. Après avoir évalué le gestionnaire de réponse, AWS AppSync traitera toutes les erreurs de contexte en les ajoutant au bloc d'erreurs de la réponse GraphQL.

**Code du gestionnaire de réponses**

```
export function response(ctx) {
  if (ctx.error) {
    util.appendError(ctx.error.message, ctx.error.type, null, ctx.result.data.unprocessedKeys);
  }
  return ctx.result.data;
}
```

Nous avons transmis à la fois l'erreur d'invocation et l'`unprocessedKeys`élément contenu dans le bloc d'erreurs de la réponse GraphQL. Le `getReadings` champ renvoie également des données partielles de la `locationReadings` table, comme vous pouvez le voir dans la réponse ci-dessous.

**Réponse GraphQL**

```
{
  "data": {
    "getReadings": [
      null,
      {
        "sensorId": "1",
        "timestamp": "2018-02-01T17:21:05.000+08:00",
        "value": 85.5
      }
    ]
  },
  "errors": [
    {
      "path": [
        "getReadings"
      ],
      "data": null,
      "errorType": "DynamoDB:ProvisionedThroughputExceededException",
      "errorInfo": {
        "temperatureReadings": [
          {
            "sensorId": "1",
            "timestamp": "2018-02-01T17:21:05.000+08:00"
          }
        ],
        "locationReadings": []
      },
      "locations": [
        {
          "line": 58,
          "column": 3
        }
      ],
      "message": "You exceeded your maximum allowed provisioned throughput for a table or for one or more global secondary indexes. (...)"
    }
  ]
}
```