

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

# Utilizzo delle operazioni batch di DynamoDB in AWS AppSync
<a name="tutorial-dynamodb-batch"></a>

**Nota**  
Ora supportiamo principalmente il runtime APPSYNC\$1JS e la relativa documentazione. [Prendi in considerazione l'utilizzo del runtime APPSYNC\$1JS e delle relative guide qui.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

AWS AppSync supporta l'utilizzo di operazioni batch di Amazon DynamoDB su una o più tabelle in una singola regione. Le operazioni supportate sono `BatchGetItem`, `BatchPutItem` e `BatchDeleteItem`. Usando queste caratteristiche in AWS AppSync, è possibile eseguire attività quali ad esempio:
+ Passare un elenco di chiavi in una singola query e restituire i risultati da una tabella
+ Leggere i record da una o più tabelle in un'unica query
+ Scrivere record in blocco in una o più tabelle
+ Scrivere o eliminare in forma condizionata record in più tabelle che possono essere relazionate

L'utilizzo delle operazioni batch con DynamoDB AWS AppSync in è una tecnica avanzata che richiede un po' di riflessione e conoscenza in più delle operazioni di backend e delle strutture delle tabelle. Inoltre, le operazioni in batch AWS AppSync presentano due differenze fondamentali rispetto alle operazioni non in batch:
+ Il ruolo dell'origine dati deve disporre delle autorizzazioni per tutte le tabelle a cui il resolver effettua l'accesso.
+ La specifica della tabella per un resolver fa parte del modello di mappatura.

## Permissions
<a name="permissions"></a>

Come altri resolver, è necessario creare un'origine dati in AWS AppSync e creare un ruolo o utilizzarne uno esistente. Poiché le operazioni batch richiedono autorizzazioni diverse sulle tabelle DynamoDB, è necessario concedere ai ruoli configurati le autorizzazioni per le azioni di lettura o scrittura:

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

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Action": [
                "dynamodb:BatchGetItem",
                "dynamodb:BatchWriteItem"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:dynamodb:us-east-1:111122223333:table/TABLENAME",
                "arn:aws:dynamodb:us-east-1:111122223333:table/TABLENAME/*"
            ]
        }
    ]
}
```

------

 **Nota**: i ruoli sono legati alle fonti di dati in AWS AppSync e i resolver sui campi vengono richiamati su un'origine dati. Le fonti di dati configurate per il recupero con DynamoDB hanno solo una tabella specificata, per semplificare la configurazione. Pertanto, quando si esegue un'operazione di batch su più tabelle in un singolo resolver, che è una delle attività più avanzate, è necessario concedere il ruolo sull'accesso all'origine dati a tutte le tabelle con cui interagirà il resolver. Questo potrebbe essere fatto nel campo **Risorsa** nella policy di IAM indicata in precedenza. Viene effettuata la configurazione delle tabelle per effettuare chiamate in batch nel modello di resolver, che verrà descritto di seguito.

## Origine dati
<a name="data-source"></a>

Per semplicità, useremo la stessa origine dati per tutti i resolver usati in questo tutorial. Nella scheda **Sorgenti dati**, crea una nuova origine dati DynamoDB e assegnale un nome. **BatchTutorial** Per la tabella è possibile specificare un qualsiasi nome, perché i nomi delle tabelle sono specificati come parte del modello di mappatura delle richieste per le operazioni in batch. La tabella si chiamerà `empty`.

Per questo tutorial, funzionerà qualsiasi ruolo con le seguenti policy inline:

## Batch a tabella singola
<a name="single-table-batch"></a>

**avvertimento**  
`BatchPutItem`e non `BatchDeleteItem` sono supportati se utilizzati per il rilevamento e la risoluzione dei conflitti. Queste impostazioni devono essere disabilitate per evitare possibili errori.

Per questo esempio, si supponga di disporre di una tabella singola denominata **Post** a cui si desidera aggiungere o rimuovere voci con operazioni in batch. Usa lo schema seguente, notando che per la query passeremo un elenco di 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]
}

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

Allegare un resolver al campo `batchAdd()` con il seguente **Modello di mappatura della richiesta**. Questo prende automaticamente ogni voce nel tipo `input PostInput`di GraphQL e crea una mappa, che è necessaria per l'operazione `BatchPutItem`:

```
#set($postsdata = [])
#foreach($item in ${ctx.args.posts})
    $util.qr($postsdata.add($util.dynamodb.toMapValues($item)))
#end

{
    "version" : "2018-05-29",
    "operation" : "BatchPutItem",
    "tables" : {
        "Posts": $utils.toJson($postsdata)
    }
}
```

In questo caso, il **Modello di mappatura della risposta** è un semplice passaggio, ma notare che il nome della tabella viene aggiunto come `..data.Posts` all'oggetto del contesto come segue:

```
$util.toJson($ctx.result.data.Posts)
```

Ora accedere alla pagina **Query** della console di AWS AppSync ed eseguire la seguente mutazione **batchAdd**:

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

**Dovresti vedere i risultati stampati sullo schermo e puoi convalidare in modo indipendente tramite la console DynamoDB che entrambi i valori sono stati scritti nella tabella Posts.**

Successivamente, allegare un resolver al campo `batchGet()` con il seguente **Modello di mappatura della richiesta**. Questo prende automaticamente ogni voce nel tipo `ids:[]` di GraphQL e crea una mappa, che risulta necessaria per l'operazione `BatchGetItem`:

```
#set($ids = [])
#foreach($id in ${ctx.args.ids})
    #set($map = {})
    $util.qr($map.put("id", $util.dynamodb.toString($id)))
    $util.qr($ids.add($map))
#end

{
    "version" : "2018-05-29",
    "operation" : "BatchGetItem",
    "tables" : {
        "Posts": {
            "keys": $util.toJson($ids),
            "consistentRead": true,
            "projection" : {
                "expression" : "#id, title",
                "expressionNames" : { "#id" : "id"}
                }
        }
    }
}
```

Il **Modello di mappatura della risposta** è ancora un semplice passaggio, con di nuovo il nome della tabella che viene aggiunto come `..data.Posts` all'oggetto del contesto:

```
$util.toJson($ctx.result.data.Posts)
```

Ora tornare alla pagina **Query** della console di AWS AppSync ed eseguire la seguente **Query di batchAdd**:

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

Questo dovrebbe restituire i risultati per i due valori `id` aggiunti in precedenza. Si noti che un valore `null` è stato restituito per `id` con un valore di `3`. Questo perché non era presente nessun record nella tabella **Post** che avesse ancora tale valore. Tieni inoltre presente che AWS AppSync restituisce i risultati nello stesso ordine delle chiavi passate alla query, una funzionalità aggiuntiva che viene eseguita per conto AWS AppSync tuo. Pertanto, se si passa a `batchGet(ids:[1,3,2)`, si visualizzerà l'ordine modificato. È inoltre possibile sapere quale `id` ha restituito un valore `null`.

Infine, allegare un resolver al campo `batchDelete()` con il seguente **Modello di mappatura della richiesta**. Questo prende automaticamente ogni voce nel tipo `ids:[]` di GraphQL e crea una mappa, che risulta necessaria per l'operazione `BatchGetItem`:

```
#set($ids = [])
#foreach($id in ${ctx.args.ids})
    #set($map = {})
    $util.qr($map.put("id", $util.dynamodb.toString($id)))
    $util.qr($ids.add($map))
#end

{
    "version" : "2018-05-29",
    "operation" : "BatchDeleteItem",
    "tables" : {
        "Posts": $util.toJson($ids)
    }
}
```

Il **Modello di mappatura della risposta** è ancora un semplice passaggio, con di nuovo il nome della tabella che viene aggiunto come `..data.Posts` all'oggetto del contesto:

```
$util.toJson($ctx.result.data.Posts)
```

Ora tornare alla pagina **Query** della console di AWS AppSync ed eseguire la seguente mutazione **batchDelete**:

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

I record con `id` `1` e `2` dovrebbero essere eliminati. Se si esegue nuovamente la query `batchGet()` da una versione precedente, questi devono restituire `null`.

## Batch a tabella multipla
<a name="multi-table-batch"></a>

**avvertimento**  
`BatchPutItem`e non `BatchDeleteItem` sono supportati se utilizzati per il rilevamento e la risoluzione dei conflitti. Queste impostazioni devono essere disabilitate per evitare possibili errori.

AWS AppSync consente inoltre di eseguire operazioni in batch su più tabelle. L'applicazione seguente è più complessa da costruire. Si immagini di creare un'app per la salute degli animali, in cui i sensori segnalano la posizione dell'animale domestico e la temperatura corporea. I sensori sono dotati di batteria e tentano di connettersi alla rete a distanza di pochi minuti. Quando un sensore stabilisce una connessione, invia le sue letture alla nostra AWS AppSync API. I trigger quindi analizzano i dati in modo da presentare un pannello di controllo al proprietario dell'animale domestico, focalizzando l'attenzione sulla rappresentazione delle interazioni tra il sensore e l'archivio di dati di back-end.

**Come prerequisito, creiamo prima due tabelle DynamoDB**;** LocationReadings memorizzerà le letture della posizione del sensore e TemperatureReadings memorizzerà le letture della temperatura del sensore.** Entrambe le tabelle condividono la stessa struttura della chiave primaria: la chiave di partizione `sensorId (String)` e la chiave di ordinamento `timestamp (String)`.

Utilizzare il seguente schema di GraphQL:

```
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
}
```

### BatchPutItem - Registrazione delle letture del sensore
<a name="batchputitem-recording-sensor-readings"></a>

I sensori devono essere in grado di inviare le loro letture una volta stabilita la connessione a Internet. Il campo `Mutation.recordReadings` di GraphQL è l'API che si userà per farlo. Allegare un resolver per portare alla vita l'API.

Selezionare **Attach (Allega)** vicino al campo `Mutation.recordReadings`. Sulla schermata successiva, scegliere la stessa origine dati `BatchTutorial` creata all'inizio di questo tutorial.

Aggiungere il seguente modello di mappatura della richiesta.

 **Modello di mappatura della richiesta** 

```
## Convert tempReadings arguments to DynamoDB objects
#set($tempReadings = [])
#foreach($reading in ${ctx.args.tempReadings})
    $util.qr($tempReadings.add($util.dynamodb.toMapValues($reading)))
#end

## Convert locReadings arguments to DynamoDB objects
#set($locReadings = [])
#foreach($reading in ${ctx.args.locReadings})
    $util.qr($locReadings.add($util.dynamodb.toMapValues($reading)))
#end

{
    "version" : "2018-05-29",
    "operation" : "BatchPutItem",
    "tables" : {
        "locationReadings": $utils.toJson($locReadings),
        "temperatureReadings": $utils.toJson($tempReadings)
    }
}
```

Come si può vedere, l'operazione `BatchPutItem` consente di specificare più tabelle.

Usare il seguente modello di mappatura della risposta.

 **Modello di mappatura della risposta** 

```
## If there was an error with the invocation
## there might have been partial results
#if($ctx.error)
    ## Append a GraphQL error for that field in the GraphQL response
    $utils.appendError($ctx.error.message, $ctx.error.message)
#end
## Also returns data for the field in the GraphQL response
$utils.toJson($ctx.result.data)
```

Con le operazioni in batch, possono essere presenti entrambi gli errori e i risultati restituiti dalla chiamata. In questo caso, è possibile eseguire liberamente ulteriori operazioni di gestione degli errori.

 **Nota**: l'uso di `$utils.appendError()` è analogo a quello di `$util.error()`, con la differenza principale che non interrompe la valutazione del modello di mappatura. Al contrario, segnala che si è verificato un errore con il campo, ma consente al modello di essere valutato e, di conseguenza, di restituire i dati al chiamante. Si consiglia di usare `$utils.appendError()` quando un'applicazione deve restituire risultati parziali.

Salva il resolver e vai alla pagina **Query della console**. AWS AppSync Inviare alcune letture del sensore.

Eseguire la mutazione seguente:

```
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
    }
  }
}
```

Sono state inviate 10 letture del sensore in una sola mutazione, con letture suddivise in due tabelle. ****Utilizza la console DynamoDB per verificare che i dati vengano visualizzati nelle tabelle LocationReadings e Temperaturereadings.****

### BatchDeleteItem - Eliminazione delle letture del sensore
<a name="batchdeleteitem-deleting-sensor-readings"></a>

Analogamente, sarebbe necessario anche eliminare i batch delle letture del sensore. Utilizzare il campo `Mutation.deleteReadings` di GraphQL per questo scopo. Selezionare **Attach (Allega)** vicino al campo `Mutation.recordReadings`. Sulla schermata successiva, scegliere la stessa origine dati `BatchTutorial` creata all'inizio di questo tutorial.

Utilizzare il seguente modello di mappatura della richiesta.

 **Modello di mappatura della richiesta** 

```
## Convert tempReadings arguments to DynamoDB primary keys
#set($tempReadings = [])
#foreach($reading in ${ctx.args.tempReadings})
    #set($pkey = {})
    $util.qr($pkey.put("sensorId", $reading.sensorId))
    $util.qr($pkey.put("timestamp", $reading.timestamp))
    $util.qr($tempReadings.add($util.dynamodb.toMapValues($pkey)))
#end

## Convert locReadings arguments to DynamoDB primary keys
#set($locReadings = [])
#foreach($reading in ${ctx.args.locReadings})
    #set($pkey = {})
    $util.qr($pkey.put("sensorId", $reading.sensorId))
    $util.qr($pkey.put("timestamp", $reading.timestamp))
    $util.qr($locReadings.add($util.dynamodb.toMapValues($pkey)))
#end

{
    "version" : "2018-05-29",
    "operation" : "BatchDeleteItem",
    "tables" : {
        "locationReadings": $utils.toJson($locReadings),
        "temperatureReadings": $utils.toJson($tempReadings)
    }
}
```

Il modello di mappatura della risposta è lo stesso utilizzato per `Mutation.recordReadings`.

 **Modello di mappatura della risposta** 

```
## If there was an error with the invocation
## there might have been partial results
#if($ctx.error)
    ## Append a GraphQL error for that field in the GraphQL response
    $utils.appendError($ctx.error.message, $ctx.error.message)
#end
## Also return data for the field in the GraphQL response
$utils.toJson($ctx.result.data)
```

Salva il resolver e vai alla pagina **Query della console**. AWS AppSync Ora, eliminare un paio di letture del sensore.

Eseguire la mutazione seguente:

```
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
    }
  }
}
```

****Verifica tramite la console DynamoDB che queste due letture siano state eliminate dalle tabelle LocationReadings e TemperatureReadings.****

### BatchGetItem - Recupera le letture
<a name="batchgetitem-retrieve-readings"></a>

Un'altra operazione comune per l'app Pet Health sarebbe quella di recuperare le letture per un sensore in un determinato momento. Allegare un resolver al campo `Query.getReadings` di GraphQL sullo schema. Selezionare **Attach (Allega)** e, sulla schermata successiva, scegliere la stessa origine dati `BatchTutorial` creata all'inizio del tutorial.

Aggiungere il seguente modello di mappatura della richiesta.

 **Modello di mappatura della richiesta** 

```
## Build a single DynamoDB primary key,
## as both locationReadings and tempReadings tables
## share the same primary key structure
#set($pkey = {})
$util.qr($pkey.put("sensorId", $ctx.args.sensorId))
$util.qr($pkey.put("timestamp", $ctx.args.timestamp))

{
    "version" : "2018-05-29",
    "operation" : "BatchGetItem",
    "tables" : {
        "locationReadings": {
            "keys": [$util.dynamodb.toMapValuesJson($pkey)],
            "consistentRead": true
        },
        "temperatureReadings": {
            "keys": [$util.dynamodb.toMapValuesJson($pkey)],
            "consistentRead": true
        }
    }
}
```

Nota che ora stiamo usando l'**BatchGetItem**operazione.

Il modello di mappatura della risposta sarà leggermente diverso perché è stato scelto di restituire un elenco `SensorReading`. Mappare il risultato della chiamata nella forma desiderata.

 **Modello di mappatura della risposta** 

```
## Merge locationReadings and temperatureReadings
## into a single list
## __typename needed as schema uses an interface
#set($sensorReadings = [])

#foreach($locReading in $ctx.result.data.locationReadings)
    $util.qr($locReading.put("__typename", "LocationReading"))
    $util.qr($sensorReadings.add($locReading))
#end

#foreach($tempReading in $ctx.result.data.temperatureReadings)
    $util.qr($tempReading.put("__typename", "TemperatureReading"))
    $util.qr($sensorReadings.add($tempReading))
#end

$util.toJson($sensorReadings)
```

Salva il resolver e vai alla pagina **Query** della console. AWS AppSync Ora, recuperare le letture del sensore.

Eseguire la query seguente:

```
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
    }
  }
}
```

Abbiamo dimostrato con successo l'uso delle operazioni batch di DynamoDB utilizzando. AWS AppSync

## Gestione errori
<a name="error-handling"></a>

Nel AWS AppSync, le operazioni sulle sorgenti dati a volte possono restituire risultati parziali. Risultati parziali è il termine che si userà per indicare quando l'output di un'operazione comprende alcuni dati e un errore. Poiché la gestione degli errori è intrinsecamente specifica dell'applicazione, AWS AppSync offre la possibilità di gestire gli errori nel modello di mappatura della risposta. L'errore di chiamata del resolver, se presente, è disponibile nel contesto come `$ctx.error`. Gli errori di chiamata comprendono sempre un messaggio e un tipo, accessibili come proprietà `$ctx.error.message` e `$ctx.error.type`. Durante la chiamata del modello di mappatura della risposta, è possibile gestire i risultati parziali in tre modi:

1. assumere l'errore di chiamata semplicemente restituendo i dati

1. generare un errore (usando `$util.error(...)`) arrestando la valutazione del modello di mappatura della risposta, che non restituisce nessun dato.

1. accodare un errore (usando `$util.appendError(...)`) e restituire anche i dati

Ora è opportuno dimostrare ciascuno dei tre punti sopra indicati con le operazioni in batch di DynamoDB.

### Operazioni di batch di DynamoDB
<a name="dynamodb-batch-operations"></a>

Con le operazioni di batch di DynamoDB, è possibile che un batch sia completato parzialmente. Ovvero, è possibile che alcune delle chiavi o voci richieste non vengano elaborate. Se non AWS AppSync è in grado di completare un batch, nel contesto verranno impostati elementi non elaborati e un errore di invocazione.

La gestione degli errori verrà realizzata tramite la configurazione del campo `Query.getReadings` dall'operazione `BatchGetItem` dalla sezione precedente di questo tutorial. In questo momento, è opportuno supporre che durante l'esecuzione del campo `Query.getReadings`, la tabella `temperatureReadings` DynamoDB esegua un throughput assegnato. DynamoDB ha generato **ProvisionedThroughputExceededException**un al secondo tentativo AWS AppSync per elaborare gli elementi rimanenti del batch.

Il seguente JSON rappresenta il contesto serializzato dopo la chiamata del batch di DynamoDB prima che il modello di mappatura della risposta venisse valutato.

```
{
  "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": []
}
```

Alcune cose da tenere presente in questo contesto:
+ **l'errore di invocazione è stato impostato nel contesto in `$ctx.error` by AWS AppSync e il tipo di errore è stato impostato su DynamoDB:. ProvisionedThroughputExceededException**
+ i risultati sono mappati per tabella in `$ctx.result.data`, anche se è presente un errore
+ le chiavi che non sono state elaborate sono disponibili in `$ctx.result.data.unprocessedKeys`. Qui, non AWS AppSync è stato possibile recuperare l'elemento con la chiave (SensorID:1, timestamp:2018-02-01T 17:21:05.000 \$1 08:00) a causa dell'insufficiente velocità di trasmissione della tabella.

 **Nota**: per `BatchPutItem`, è `$ctx.result.data.unprocessedItems`. Per `BatchDeleteItem`, è `$ctx.result.data.unprocessedKeys`.

È possibile gestire l'errore in tre modi diversi.

#### 1. Assumere l'errore di chiamata
<a name="swallowing-the-invocation-error"></a>

Restituire i dati senza gestire l'errore di chiamata assume efficacemente l'errore. In questo modo, il risultato per il campo di GraphQL è sempre positivo.

Il modello di mappatura della risposta che viene scritto è familiare e si focalizza solo sui dati del risultato.

Modello di mappatura della risposta:

```
$util.toJson($ctx.result.data)
```

Risposta di 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
      }
    ]
  }
}
```

Non verrà aggiunto nessun errore alla risposta di errore poiché sono stati eseguiti solo i dati.

#### 2. Generazione di un errore per interrompere l'esecuzione del modello
<a name="raising-an-error-to-abort-the-template-execution"></a>

Quando i guasti parziali devono essere trattati come guasti totali dalla prospettiva del client, è possibile interrompere l'esecuzione del modello per evitare di restituire i dati. Il metodo di utilità `$util.error(...)` raggiunge esattamente questo comportamento.

Modello di mappatura della risposta:

```
## there was an error let's mark the entire field
## as failed and do not return any data back in the response
#if ($ctx.error)
    $util.error($ctx.error.message, $ctx.error.type, null, $ctx.result.data.unprocessedKeys)
#end

$util.toJson($ctx.result.data)
```

Risposta di 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. (...)"
    }
  ]
}
```

Sebbene alcuni risultati possano essere stati restituiti dall'operazione in batch di DynamoDB, si è scelto di generare un errore in modo tale che il campo `getReadings` di GraphQL sia nullo e l'errore venga aggiunto al blocco di *errori* della risposta GraphQL.

#### 3. Aggiunta di un errore per restituire sia i dati sia gli errori
<a name="appending-an-error-to-return-both-data-and-errors"></a>

In alcuni casi, per fornire una migliore esperienza utente, le applicazioni possono restituire risultati parziali e notificare ai client le voci non elaborate. I client possono decidere di implementare un nuovo tentativo oppure di rimandare l'errore all'utente finale. Il `$util.appendError(...)` è il metodo di utilità che consente questo comportamento, permettendo al designer dell'applicazione di accodare gli errori nel contesto senza interferire con la valutazione del modello. Dopo aver valutato il modello, AWS AppSync elaborerà eventuali errori di contesto aggiungendoli al blocco errors della risposta GraphQL.

Modello di mappatura della risposta:

```
#if ($ctx.error)
    ## pass the unprocessed keys back to the caller via the `errorInfo` field
    $util.appendError($ctx.error.message, $ctx.error.type, null, $ctx.result.data.unprocessedKeys)
#end

$util.toJson($ctx.result.data)
```

Sono stati inoltrati sia l'errore di chiamata sia l'elemento unprocessedKeys all'interno del blocco di errori della risposta di GraphQL. Anche il campo `getReadings` restituisce dati parziali dalla tabella **locationReadings** come è possibile vedere nella risposta di seguito.

Risposta di 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. (...)"
    }
  ]
}
```