

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à.

# JavaScript tutorial resolver per AWS AppSync
<a name="tutorials-js"></a>

Le sorgenti di dati e i resolver vengono utilizzati per AWS AppSync tradurre le richieste GraphQL e recuperare informazioni dalle tue risorse. AWS AWS AppSync supporta il provisioning automatico e le connessioni con determinati tipi di fonti di dati. AWS AppSync supporta anche Amazon DynamoDB AWS Lambda, database relazionali (Amazon Aurora Serverless), OpenSearch Amazon Service ed endpoint HTTP come fonti di dati. Puoi utilizzare un'API GraphQL con le tue AWS risorse esistenti o creare sorgenti di dati e resolver partendo da zero. Le sezioni seguenti hanno lo scopo di chiarire alcuni dei casi d'uso più comuni di GraphQL sotto forma di tutorial.

**Topics**
+ [Creazione di una semplice applicazione post utilizzando i resolver DynamoDB JavaScript](tutorial-dynamodb-resolvers-js.md)
+ [AWS Lambda Usare i resolver](tutorial-lambda-resolvers-js.md)
+ [Utilizzo di resolver locali](tutorial-local-resolvers-js.md)
+ [Combinazione di resolver GraphQL](tutorial-combining-graphql-resolvers-js.md)
+ [Utilizzo dei resolver di servizio OpenSearch](tutorial-elasticsearch-resolvers-js.md)
+ [Esecuzione di transazioni DynamoDB](tutorial-dynamodb-transact-js.md)
+ [Utilizzo delle operazioni batch di DynamoDB](tutorial-dynamodb-batch-js.md)
+ [Utilizzo di resolver HTTP](tutorial-http-resolvers-js.md)
+ [Usare Aurora PostgreSQL con Data API](aurora-serverless-tutorial-js.md)

# Creazione di una semplice applicazione post utilizzando i resolver DynamoDB JavaScript
<a name="tutorial-dynamodb-resolvers-js"></a>

In questo tutorial, importerai le tue tabelle Amazon DynamoDB e le AWS AppSync collegherai per creare un'API GraphQL completamente funzionale JavaScript utilizzando resolver di pipeline che puoi sfruttare nella tua applicazione.

Utilizzerai la AWS AppSync console per effettuare il provisioning delle tue risorse Amazon DynamoDB, creare i tuoi resolver e collegarli alle tue fonti di dati. Potrai anche leggere e scrivere sul tuo database Amazon DynamoDB tramite istruzioni GraphQL e sottoscrivere dati in tempo reale.

Esistono passaggi specifici che devono essere completati per tradurre le istruzioni GraphQL nelle operazioni di Amazon DynamoDB e per ritradurre le risposte in GraphQL. Questo tutorial descrive il processo di configurazione attraverso diversi scenari e modelli di accesso ai dati reali.

## Creazione dell'API GraphQL
<a name="create-graphql-api"></a>

**Per creare un'API GraphQL in AWS AppSync**

1. Apri la AppSync console e scegli **Crea API**.

1. Seleziona **Design da zero** e scegli **Avanti**.

1. Assegna un nome alla tua API`PostTutorialAPI`, quindi scegli **Avanti**. Passa alla pagina di revisione mantenendo le altre opzioni impostate sui valori predefiniti e scegli`Create`.

La AWS AppSync console crea una nuova API GraphQL per te. Per impostazione predefinita, utilizza la modalità di autenticazione tramite chiave API. Puoi usare la console per configurare ulteriormente l'API GraphQL ed eseguire query sull'API per le parti restanti di questo tutorial.

## Definizione di un'API post di base
<a name="define-post-api"></a>

Ora che hai la tua API GraphQL, puoi configurare uno schema di base che consenta la creazione, il recupero e l'eliminazione di base dei dati post.

**Per aggiungere dati allo schema**

1. Nella tua API, scegli la scheda **Schema**.

1. Creeremo uno schema che definisce un `Post` tipo e un'operazione `addPost` per aggiungere e ottenere `Post` oggetti. Nel riquadro **Schema**, sostituisci il contenuto con il seguente codice:

   ```
   schema {
       query: Query
       mutation: Mutation
   }
   
   type Query {
       getPost(id: ID): Post
   }
   
   type Mutation {
       addPost(
           id: ID!
           author: String!
           title: String!
           content: String!
           url: String!
       ): Post!
   }
   
   type Post {
       id: ID!
       author: String
       title: String
       content: String
       url: String
       ups: Int!
       downs: Int!
       version: Int!
   }
   ```

1. Scegli **Save Scheme (Salva schema)**.

## Configurazione della tabella Amazon DynamoDB
<a name="configure-dynamodb"></a>

La AWS AppSync console può aiutarti a fornire le AWS risorse necessarie per archiviare le tue risorse in una tabella Amazon DynamoDB. In questo passaggio, creerai una tabella Amazon DynamoDB per archiviare i tuoi post. Inoltre, configurerai un [indice secondario](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/SecondaryIndexes.html) che utilizzeremo in seguito.

**Per creare la tua tabella Amazon DynamoDB**

1. Nella pagina **Schema**, scegli **Crea** risorse.

1. Scegli **Usa il tipo esistente**, quindi scegli il `Post` tipo.

1. Nella sezione **Indici aggiuntivi**, scegli **Aggiungi** indice.

1. Assegna un nome all'indice. `author-index`

1. Imposta `Primary key` a `author` e la `Sort` chiave a`None`.

1. Disabilita la **generazione automatica di GraphQL**. In questo esempio, creeremo noi stessi il resolver.

1. Scegli **Create** (Crea).

Ora hai una nuova fonte di dati chiamata`PostTable`, che puoi vedere visitando **Fonti di dati** nella scheda laterale. Utilizzerai questa fonte di dati per collegare le tue query e mutazioni alla tua tabella Amazon DynamoDB. 

## Configurazione di un resolver AddPost (Amazon DynamoDB) PutItem
<a name="configure-addpost"></a>

Ora che conosci AWS AppSync la tabella Amazon DynamoDB, puoi collegarla a singole query e mutazioni definendo i resolver. Il primo resolver che crei è il resolver di `addPost` pipeline utilizzato JavaScript, che ti consente di creare un post nella tua tabella Amazon DynamoDB. Un risolutore di pipeline ha i seguenti componenti: 
+ Posizione nello schema GraphQL per collegare il resolver. In questo caso, stai configurando un resolver nel campo `createPost` nel tipo `Mutation`. Questo resolver verrà richiamato quando il chiamante chiama mutation. `{ addPost(...){...} }` 
+ Origine dati da usare per il resolver. In questo caso, si desidera utilizzare l'origine dati DynamoDB definita in precedenza, in modo da poter aggiungere voci nella tabella DynamoDB. `post-table-for-tutorial`
+ Il gestore delle richieste. Il gestore delle richieste è una funzione che gestisce la richiesta in entrata dal chiamante e la traduce in istruzioni da AWS AppSync eseguire su DynamoDB.
+ Il gestore delle risposte. Il compito del gestore delle risposte è gestire la risposta da DynamoDB e tradurla nuovamente in qualcosa che GraphQL si aspetta. Questo è utile se la forma dei dati in DynamoDB è diversa rispetto al tipo `Post` in GraphQL, ma in questo caso hanno la stessa forma e di conseguenza puoi semplicemente passare i dati. 

**Per configurare il resolver**

1. Nella tua API, scegli la scheda **Schema**.

1. **Nel **riquadro Resolver**, trova il `addPost` campo sotto il `Mutation` tipo, quindi scegli Allega.**

1. **Scegli la tua fonte di dati, quindi scegli Crea.**

1. Nel tuo editor di codice, sostituisci il codice con questo frammento:

   ```
   import { util } from '@aws-appsync/utils'
   import * as ddb from '@aws-appsync/utils/dynamodb'
   
   export function request(ctx) {
   	const item = { ...ctx.arguments, ups: 1, downs: 0, version: 1 }
   	const key = { id: ctx.args.id ?? util.autoId() }
   	return ddb.put({ key, item })
   }
   
   export function response(ctx) {
   	return ctx.result
   }
   ```

1. Scegli **Save** (Salva).

**Nota**  
In questo codice, si utilizzano gli utils del modulo DynamoDB che consentono di creare facilmente richieste DynamoDB.

AWS AppSync viene fornito con un'utilità per la generazione automatica di ID chiamata`util.autoId()`, che viene utilizzata per generare un ID per il nuovo post. Se non specifichi un ID, l'utilità lo genererà automaticamente per te.

```
const key = { id: ctx.args.id ?? util.autoId() }
```

Per ulteriori informazioni sulle utilità disponibili per JavaScript, consulta [Funzionalità JavaScript di runtime per resolver e funzioni](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference-js.html). 

### Chiama l'API per aggiungere un post
<a name="call-api-addpost"></a>

Ora che il resolver è stato configurato, AWS AppSync puoi tradurre una `addPost` mutazione in entrata in un'operazione Amazon DynamoDB. `PutItem` Puoi ora eseguire una mutazione per inserire contenuto nella tabella.

**Per eseguire l'operazione**

1. Nella tua API, scegli la scheda **Query**.

1. Nel riquadro **Query**, aggiungi la seguente mutazione:

   ```
   mutation addPost {
     addPost(
       id: 123,
       author: "AUTHORNAME"
       title: "Our first post!"
       content: "This is our first post."
       url: "https://aws.amazon.com/appsync/"
     ) {
       id
       author
       title
       content
       url
       ups
       downs
       version
     }
   }
   ```

1. Scegli **Esegui** (il pulsante arancione di riproduzione), quindi scegli. `addPost` I risultati del post appena creato dovrebbero apparire nel riquadro **Risultati** a destra del riquadro **Query**. La schermata visualizzata dovrebbe risultare simile a quella nell'immagine seguente:

   ```
   {
     "data": {
       "addPost": {
         "id": "123",
         "author": "AUTHORNAME",
         "title": "Our first post!",
         "content": "This is our first post.",
         "url": "https://aws.amazon.com/appsync/",
         "ups": 1,
         "downs": 0,
         "version": 1
       }
     }
   }
   ```

La seguente spiegazione mostra cosa è successo:

1. AWS AppSync ha ricevuto una richiesta di `addPost` mutazione.

1. AWS AppSync esegue il gestore delle richieste del resolver. La `ddb.put` funzione crea una `PutItem` richiesta simile alla seguente:

   ```
   {
     operation: 'PutItem',
     key: { id: { S: '123' } },
     attributeValues: {
       downs: { N: 0 },
       author: { S: 'AUTHORNAME' },
       ups: { N: 1 },
       title: { S: 'Our first post!' },
       version: { N: 1 },
       content: { S: 'This is our first post.' },
       url: { S: 'https://aws.amazon.com/appsync/' }
     }
   }
   ```

1. AWS AppSync utilizza questo valore per generare ed eseguire una richiesta Amazon `PutItem` DynamoDB.

1. AWS AppSync ha preso i risultati della `PutItem` richiesta e li ha riconvertiti in tipi GraphQL.

   ```
   {
       "id" : "123",
       "author": "AUTHORNAME",
       "title": "Our first post!",
       "content": "This is our first post.",
       "url": "https://aws.amazon.com/appsync/",
       "ups" : 1,
       "downs" : 0,
       "version" : 1
   }
   ```

1. Il gestore della risposta restituisce immediatamente il risultato ()`return ctx.result`.

1. Il risultato finale è visibile nella risposta GraphQL.

## Configurazione del resolver GetPost (Amazon DynamoDB) GetItem
<a name="configure-getpost"></a>

Ora che sei in grado di aggiungere dati alla tabella Amazon DynamoDB, devi configurare `getPost` la query in modo che possa recuperare i dati dalla tabella. A questo scopo, devi configurare un altro resolver.

**Per aggiungere il tuo resolver**

1. Nella tua API, scegli la scheda **Schema**.

1. **Nel **riquadro Resolver** a destra, trova il `getPost` campo relativo al `Query` tipo, quindi scegli Allega.**

1. **Scegli la tua fonte di dati, quindi scegli Crea.**

1. Nell'editor di codice, sostituisci il codice con questo frammento:

   ```
   import * as ddb from '@aws-appsync/utils/dynamodb'
   	
   export function request(ctx) {
   	return ddb.get({ key: { id: ctx.args.id } })
   }
   
   export const response = (ctx) => ctx.result
   ```

1. Salva il resolver.

**Nota**  
In questo resolver, utilizziamo un'espressione della funzione freccia per il gestore delle risposte.

### Chiama l'API per ricevere un post
<a name="call-api-getpost"></a>

Ora che il resolver è stato configurato, AWS AppSync sa come tradurre una `getPost` query in entrata in un'operazione Amazon DynamoDB. `GetItem` Puoi ora eseguire una query per recuperare il post creato prima.

**Per eseguire la tua query**

1. Nella tua API, scegli la scheda **Query**. 

1. Nel riquadro **Query**, aggiungi il codice seguente e usa l'id che hai copiato dopo aver creato il post:

   ```
   query getPost {
     getPost(id: "123") {
       id
       author
       title
       content
       url
       ups
       downs
       version
     }
   }
   ```

1. Scegli **Esegui** (il pulsante arancione di riproduzione), quindi scegli. `getPost` I risultati del post appena creato dovrebbero apparire nel riquadro **Risultati** a destra del riquadro **Query**.

1. **Il post recuperato da Amazon DynamoDB dovrebbe apparire **nel riquadro Risultati a** destra del riquadro Query.** La schermata visualizzata dovrebbe risultare simile a quella nell'immagine seguente:

   ```
   {
     "data": {
       "getPost": {
         "id": "123",
         "author": "AUTHORNAME",
         "title": "Our first post!",
         "content": "This is our first post.",
         "url": "https://aws.amazon.com/appsync/",
         "ups": 1,
         "downs": 0,
         "version": 1
       }
     }
   }
   ```

In alternativa, prendi il seguente esempio:

```
query getPost {
  getPost(id: "123") {
    id
    author
    title
  }
}
```

Se la tua `getPost` query richiede solo il`id`, e `author``title`, puoi modificare la funzione di richiesta per utilizzare le espressioni di proiezione per specificare solo gli attributi che desideri dalla tua tabella DynamoDB per evitare trasferimenti di dati non necessari da DynamoDB a. AWS AppSync Ad esempio, la funzione di richiesta può essere simile allo snippet riportato di seguito:

```
import * as ddb from '@aws-appsync/utils/dynamodb'

export function request(ctx) {
	return ddb.get({
		key: { id: ctx.args.id },
		projection: ['author', 'id', 'title'],
	})
}

export const response = (ctx) => ctx.result
```

Puoi anche usare un [selectionSetList](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html#aws-appsync-resolver-context-reference-info-js)with `getPost` per rappresentare: `expression`

```
import * as ddb from '@aws-appsync/utils/dynamodb'

export function request(ctx) {
	const projection = ctx.info.selectionSetList.map((field) => field.replace('/', '.'))
	return ddb.get({ key: { id: ctx.args.id }, projection })
}

export const response = (ctx) => ctx.result
```

## Creare una mutazione UpdatePost (Amazon DynamoDB) UpdateItem
<a name="configure-updatepost"></a>

Finora, puoi creare e recuperare `Post` oggetti in Amazon DynamoDB. Successivamente, imposterai una nuova mutazione per aggiornare un oggetto. Rispetto alla `addPost` mutazione che richiede la specificazione di tutti i campi, questa mutazione consente di specificare solo i campi che si desidera modificare. Ha inoltre introdotto un nuovo `expectedVersion` argomento che consente di specificare la versione che si desidera modificare. Imposterete una condizione che assicurerà che stiate modificando la versione più recente dell'oggetto. Potrai farlo utilizzando `UpdateItem` Amazon DynamoDB operation.sc

**Per aggiornare il resolver**

1. Nella tua API, scegli la scheda **Schema**.

1. Nel riquadro **Schema**, modificare il tipo `Mutation` per aggiungere una nuova mutazione `updatePost` come segue:

   ```
   type Mutation {
       updatePost(
           id: ID!,
           author: String,
           title: String,
           content: String,
           url: String,
           expectedVersion: Int!
       ): Post
       
       addPost(
           id: ID
           author: String!
           title: String!
           content: String!
           url: String!
       ): Post!
   }
   ```

1. Scegli **Save Scheme (Salva schema)**.

1. **Nel **riquadro Resolver** a destra, trova il `updatePost` campo appena creato relativo al `Mutation` tipo, quindi scegli Allega.** Crea il tuo nuovo resolver usando lo snippet qui sotto:

   ```
   import { util } from '@aws-appsync/utils';
   import * as ddb from '@aws-appsync/utils/dynamodb';
   
   export function request(ctx) {
     const { id, expectedVersion, ...rest } = ctx.args;
     const values = Object.entries(rest).reduce((obj, [key, value]) => {
       obj[key] = value ?? ddb.operations.remove();
       return obj;
     }, {});
   
     return ddb.update({
       key: { id },
       condition: { version: { eq: expectedVersion } },
       update: { ...values, version: ddb.operations.increment(1) },
     });
   }
   
   export function response(ctx) {
     const { error, result } = ctx;
     if (error) {
       util.appendError(error.message, error.type);
     }
     return result;
   ```

1. Salva tutte le modifiche apportate.

Questo resolver viene utilizzato `ddb.update` per creare una richiesta Amazon DynamoDB. `UpdateItem` Invece di scrivere l'intero articolo, stai semplicemente chiedendo ad Amazon DynamoDB di aggiornare determinati attributi. Questa operazione viene eseguita utilizzando le espressioni di aggiornamento di Amazon DynamoDB.

La `ddb.update` funzione accetta una chiave e un oggetto di aggiornamento come argomenti. Quindi, si controllano i valori degli argomenti in entrata. Quando un valore è impostato su`null`, utilizzate l'operazione `remove` DynamoDB per segnalare che il valore deve essere rimosso dall'elemento DynamoDB.

C'è anche una nuova sezione. `condition` Un'espressione di condizione consente di indicare AWS AppSync ad Amazon DynamoDB se la richiesta deve avere successo o meno in base allo stato dell'oggetto già in Amazon DynamoDB prima dell'esecuzione dell'operazione. In questo caso, vuoi che la `UpdateItem` richiesta abbia esito positivo solo se il `version` campo dell'elemento attualmente in Amazon DynamoDB corrisponde `expectedVersion` esattamente all'argomento. Quando l'elemento viene aggiornato, vogliamo incrementare il valore di. `version` Questo è facile da fare con la funzione `increment` operativa.

Per ulteriori informazioni sulle espressioni condizionali, consulta la documentazione sulle [espressioni di condizione](https://docs.aws.amazon.com/appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-condition-expressions).

Per maggiori informazioni sulla `UpdateItem` richiesta, consulta la [UpdateItem](https://docs.aws.amazon.com/appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-updateitem)documentazione e la documentazione del modulo [DynamoDB](https://docs.aws.amazon.com/appsync/latest/devguide/built-in-modules-js.html). 

Per ulteriori informazioni su come scrivere espressioni di aggiornamento, consulta la documentazione di [ UpdateExpressionsDynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html).

### Chiama l'API per aggiornare un post
<a name="call-api-updatepost"></a>

Proviamo ad aggiornare l'`Post`oggetto con il nuovo resolver.

**Per aggiornare l'oggetto**

1. Nella tua API, scegli la scheda **Query**.

1. Nel riquadro **Query**, aggiungi la seguente mutazione. Dovrai anche aggiornare l'`id`argomento al valore annotato in precedenza:

   ```
   mutation updatePost {
     updatePost(
       id:123
       title: "An empty story"
       content: null
       expectedVersion: 1
     ) {
       id
       author
       title
       content
       url
       ups
       downs
       version
     }
   }
   ```

1. Scegli **Esegui** (il pulsante arancione di riproduzione), quindi scegli`updatePost`.

1. **Il post aggiornato in Amazon DynamoDB dovrebbe apparire nel riquadro Risultati a destra **del** riquadro Query.** La schermata visualizzata dovrebbe risultare simile a quella nell'immagine seguente:

   ```
   {
     "data": {
       "updatePost": {
         "id": "123",
         "author": "A new author",
         "title": "An empty story",
         "content": null,
         "url": "https://aws.amazon.com/appsync/",
         "ups": 1,
         "downs": 0,
         "version": 2
       }
     }
   }
   ```

In questa richiesta, hai chiesto ad Amazon DynamoDB di aggiornare `title` solo i campi AWS AppSync and. `content` Tutti gli altri campi sono stati lasciati soli (a parte l'incremento del `version` campo). Hai impostato l'`title`attributo su un nuovo valore e rimosso l'`content`attributo dal post. I campi `author`, `url`, `ups` e `downs` sono stati lasciati invariati. Prova a eseguire nuovamente la richiesta di mutazione lasciando la richiesta esattamente com'è. Noterai una risposta simile alla seguente:

```
{
  "data": {
    "updatePost": null
  },
  "errors": [
    {
      "path": [
        "updatePost"
      ],
      "data": null,
      "errorType": "DynamoDB:ConditionalCheckFailedException",
      "errorInfo": null,
      "locations": [
        {
          "line": 2,
          "column": 3,
          "sourceName": null
        }
      ],
      "message": "The conditional request failed (Service: DynamoDb, Status Code: 400, Request ID: 1RR3QN5F35CS8IV5VR4OQO9NNBVV4KQNSO5AEMVJF66Q9ASUAAJG)"
    }
  ]
}
```

La richiesta fallisce perché l'espressione della condizione restituisce: `false` 

1. La prima volta che hai eseguito la richiesta, il valore del `version` campo del post in Amazon DynamoDB `1` era corrispondente all'argomento. `expectedVersion` La richiesta è riuscita, il che significa che il `version` campo è stato incrementato in Amazon DynamoDB a. `2`

1. La seconda volta che hai eseguito la richiesta, il valore del `version` campo del post in Amazon DynamoDB `2` era, che non corrispondeva all'argomento. `expectedVersion`

Questo modello viene in genere chiamato *blocco ottimistico*.

## Crea mutazioni di voto (Amazon DynamoDB UpdateItem)
<a name="configure-vote-mutations"></a>

Il `Post` tipo contiene `downs` campi per consentire la registrazione di voti positivi `ups` e negativi. Tuttavia, al momento, l'API non ci consente di fare nulla con loro. Aggiungiamo una mutazione per consentirci di votare positivamente e negativamente i post.

**Per aggiungere la tua mutazione**

1. Nella tua API, scegli la scheda **Schema**.

1. Nel riquadro **Schema**, modifica il `Mutation` tipo e aggiungi l'`DIRECTION`enum per aggiungere nuove mutazioni di voto:

   ```
   type Mutation {
       vote(id: ID!, direction: DIRECTION!): Post
       updatePost(
           id: ID!,
           author: String,
           title: String,
           content: String,
           url: String,
           expectedVersion: Int!
       ): Post
       addPost(
           id: ID,
           author: String!,
           title: String!,
           content: String!,
           url: String!
       ): Post!
   }
   
   enum DIRECTION {
     UP
     DOWN
   }
   ```

1. Scegli **Save Scheme (Salva schema)**.

1. **Nel **riquadro Resolver** a destra, individuate il `vote` campo appena creato relativo al `Mutation` tipo, quindi scegliete Allega.** Crea un nuovo resolver creando e sostituendo il codice con il seguente frammento:

   ```
   import * as ddb from '@aws-appsync/utils/dynamodb';
   
   export function request(ctx) {
     const field = ctx.args.direction === 'UP' ? 'ups' : 'downs';
     return ddb.update({
       key: { id: ctx.args.id },
       update: {
         [field]: ddb.operations.increment(1),
         version: ddb.operations.increment(1),
       },
     });
   }
   
   export const response = (ctx) => ctx.result;
   ```

1. Salva tutte le modifiche apportate.

### Chiama l'API per dare un voto positivo o negativo a un post
<a name="call-api-vote"></a>

Ora che i nuovi resolver sono stati configurati, AWS AppSync sa come tradurre una modifica `upvotePost` o una `downvote` mutazione in entrata in un'operazione Amazon DynamoDB. `UpdateItem` Ora puoi eseguire mutazioni per assegnare voti positivi e voti negativi al post creato prima.

**Per eseguire la tua mutazione**

1. Nella tua API, scegli la scheda **Query**.

1. Nel riquadro **Query**, aggiungi la seguente mutazione. Dovrai anche aggiornare l'`id`argomento al valore annotato in precedenza:

   ```
   mutation votePost {
     vote(id:123, direction: UP) {
       id
       author
       title
       content
       url
       ups
       downs
       version
     }
   }
   ```

1. Scegli **Esegui** (il pulsante arancione di riproduzione), quindi scegli`votePost`.

1. **Il post aggiornato in Amazon DynamoDB dovrebbe apparire nel riquadro Risultati a destra **del** riquadro Query.** La schermata visualizzata dovrebbe risultare simile a quella nell'immagine seguente:

   ```
   {
     "data": {
       "vote": {
         "id": "123",
         "author": "A new author",
         "title": "An empty story",
         "content": null,
         "url": "https://aws.amazon.com/appsync/",
         "ups": 6,
         "downs": 0,
         "version": 4
       }
     }
   }
   ```

1. Scegli **Esegui** ancora un paio di volte. Dovresti vedere i `version` campi `ups` and incrementare `1` ogni volta che esegui la query.

1. Cambia la query per chiamarla con un'altra`DIRECTION`.

   ```
   mutation votePost {
     vote(id:123, direction: DOWN) {
       id
       author
       title
       content
       url
       ups
       downs
       version
     }
   }
   ```

1. Scegli **Esegui** (il pulsante di riproduzione arancione), quindi scegli`votePost`.

   Questa volta, dovresti vedere i `version` campi `downs` and incrementarsi `1` ogni volta che esegui la query.

## Configurazione di un resolver DeletePost (Amazon DynamoDB) DeleteItem
<a name="configure-deletepost"></a>

Successivamente, ti consigliamo di creare una mutazione per eliminare un post. A tale scopo, utilizzerai l'operazione `DeleteItem` Amazon DynamoDB.

**Per aggiungere la tua mutazione**

1. Nel tuo schema, scegli la scheda **Schema**.

1. Nel riquadro **Schema**, modifica il `Mutation` tipo per aggiungere una nuova `deletePost` mutazione:

   ```
   type Mutation {
       deletePost(id: ID!, expectedVersion: Int): Post
       vote(id: ID!, direction: DIRECTION!): Post
       updatePost(
           id: ID!,
           author: String,
           title: String,
           content: String,
           url: String,
           expectedVersion: Int!
       ): Post
       addPost(
           id: ID
           author: String!,
           title: String!,
           content: String!,
           url: String!
       ): Post!
   }
   ```

1. Questa volta, hai reso il `expectedVersion` campo facoltativo. Quindi, scegli **Salva schema**.

1. **Nel **riquadro Resolver** a destra, trova il `delete` campo appena creato nel `Mutation` tipo, quindi scegli Allega.** Crea un nuovo resolver utilizzando il seguente codice:

   ```
   import { util } from '@aws-appsync/utils'
   
   import { util } from '@aws-appsync/utils';
   import * as ddb from '@aws-appsync/utils/dynamodb';
   
   export function request(ctx) {
     let condition = null;
     if (ctx.args.expectedVersion) {
       condition = {
         or: [
           { id: { attributeExists: false } },
           { version: { eq: ctx.args.expectedVersion } },
         ],
       };
     }
     return ddb.remove({ key: { id: ctx.args.id }, condition });
   }
   
   export function response(ctx) {
     const { error, result } = ctx;
     if (error) {
       util.appendError(error.message, error.type);
     }
     return result;
   }
   ```
**Nota**  
L'`expectedVersion`argomento è un argomento facoltativo. Se il chiamante imposta un `expectedVersion` argomento nella richiesta, il gestore della richiesta aggiunge una condizione che consente alla `DeleteItem` richiesta di avere successo solo se l'elemento è già stato eliminato o se l'`version`attributo del post in Amazon DynamoDB corrisponde esattamente a. `expectedVersion` Se non viene inserito, nessuna espressione di condizione viene specificata nella richiesta `DeleteItem`. Ha successo indipendentemente dal valore o dall'esistenza `version` o meno dell'elemento in Amazon DynamoDB.  
Anche se stai eliminando un articolo, puoi restituire l'elemento che è stato eliminato, se non lo era già.

Per maggiori informazioni sulla `DeleteItem` richiesta, consulta la [DeleteItem](https://docs.aws.amazon.com/appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-deleteitem)documentazione.

### Chiama l'API per eliminare un post
<a name="call-api-delete"></a>

Ora che il resolver è stato configurato, AWS AppSync sa come tradurre una `delete` mutazione in entrata in un'operazione Amazon DynamoDB. `DeleteItem` Puoi ora eseguire una mutazione per eliminare qualcosa nella tabella.

**Per eseguire la tua mutazione**

1. Nella tua API, scegli la scheda **Query**.

1. Nel riquadro **Query**, aggiungi la seguente mutazione. Dovrai anche aggiornare l'`id`argomento al valore annotato in precedenza:

   ```
   mutation deletePost {
     deletePost(id:123) {
       id
       author
       title
       content
       url
       ups
       downs
       version
     }
   }
   ```

1. Scegli **Esegui** (il pulsante arancione di riproduzione), quindi scegli`deletePost`.

1. Il post viene eliminato da Amazon DynamoDB. **Tieni presente che AWS AppSync restituisce il valore dell'elemento che è stato eliminato da Amazon DynamoDB, che dovrebbe apparire nel riquadro Risultati a destra **del** riquadro Query.** La schermata visualizzata dovrebbe risultare simile a quella nell'immagine seguente:

   ```
   {
     "data": {
       "deletePost": {
         "id": "123",
         "author": "A new author",
         "title": "An empty story",
         "content": null,
         "url": "https://aws.amazon.com/appsync/",
         "ups": 6,
         "downs": 4,
         "version": 12
       }
     }
   }
   ```

1. Il valore viene restituito solo se questa chiamata a `deletePost` è quella che lo elimina effettivamente da Amazon DynamoDB. **Scegli nuovamente Esegui.**

1. La chiamata riesce ancora, ma non viene restituito alcun valore:

   ```
   {
     "data": {
       "deletePost": null
     }
   }
   ```

1. Ora, proviamo a eliminare un post, ma questa volta specificando un. `expectedValue` Innanzitutto, devi creare un nuovo post perché hai appena eliminato quello con cui hai lavorato finora.

1. Nel riquadro **Query**, aggiungi la seguente mutazione:

   ```
   mutation addPost {
     addPost(
       id:123
       author: "AUTHORNAME"
       title: "Our second post!"
       content: "A new post."
       url: "https://aws.amazon.com/appsync/"
     ) {
       id
       author
       title
       content
       url
       ups
       downs
       version
     }
   }
   ```

1. Scegli **Esegui** (il pulsante arancione di riproduzione), quindi scegli. `addPost`

1. I risultati del post appena creato dovrebbero apparire nel riquadro **Risultati** a destra del riquadro **Query**. Registra `id` l'oggetto appena creato perché ti servirà in un attimo. La schermata visualizzata dovrebbe risultare simile a quella nell'immagine seguente:

   ```
   {
     "data": {
       "addPost": {
         "id": "123",
         "author": "AUTHORNAME",
         "title": "Our second post!",
         "content": "A new post.",
         "url": "https://aws.amazon.com/appsync/",
         "ups": 1,
         "downs": 0,
         "version": 1
       }
     }
   }
   ```

1. Ora, proviamo a eliminare quel post con un valore illegale per **ExpectedVersion**. Nel riquadro **Query**, aggiungi la seguente mutazione. Dovrai anche aggiornare l'`id`argomento al valore annotato in precedenza:

   ```
   mutation deletePost {
     deletePost(
       id:123
       expectedVersion: 9999
     ) {
       id
       author
       title
       content
       url
       ups
       downs
       version
     }
   }
   ```

1. Scegli **Esegui** (il pulsante arancione di riproduzione), quindi scegli`deletePost`. Viene restituito il seguente risultato:

   ```
   {
     "data": {
       "deletePost": null
     },
     "errors": [
       {
         "path": [
           "deletePost"
         ],
         "data": null,
         "errorType": "DynamoDB:ConditionalCheckFailedException",
         "errorInfo": null,
         "locations": [
           {
             "line": 2,
             "column": 3,
             "sourceName": null
           }
         ],
         "message": "The conditional request failed (Service: DynamoDb, Status Code: 400, Request ID: 7083O037M1FTFRK038A4CI9H43VV4KQNSO5AEMVJF66Q9ASUAAJG)"
       }
     ]
   }
   ```

1. La richiesta non è riuscita perché l'espressione della condizione restituisce. `false` Il valore `version` del post in Amazon DynamoDB non corrisponde a quello specificato `expectedValue` negli argomenti. Il valore corrente dell'oggetto viene restituito nel campo `data` nella sezione `errors` della risposta GraphQL. Riprova la richiesta, correggendo il valore di `expectedVersion`: 

   ```
   mutation deletePost {
     deletePost(
       id:123
       expectedVersion: 1
     ) {
       id
       author
       title
       content
       url
       ups
       downs
       version
     }
   }
   ```

1. Scegli **Esegui** (il pulsante arancione di riproduzione), quindi scegli. `deletePost` 

   Questa volta la richiesta ha esito positivo e viene restituito il valore che è stato eliminato da Amazon DynamoDB:

   ```
   {
     "data": {
       "deletePost": {
         "id": "123",
         "author": "AUTHORNAME",
         "title": "Our second post!",
         "content": "A new post.",
         "url": "https://aws.amazon.com/appsync/",
         "ups": 1,
         "downs": 0,
         "version": 1
       }
     }
   }
   ```

1. **Scegli di nuovo Esegui.** La chiamata riesce ancora, ma questa volta non viene restituito alcun valore perché il post è già stato eliminato in Amazon DynamoDB.

   ```
   { "data": { "deletePost": null } }
   ```

## Configurazione di un resolver AllPost (Amazon DynamoDB Scan)
<a name="configure-allpost"></a>

Finora, l'API è utile solo se conosci ogni post che vuoi guardare. `id` Aggiungiamo ora un nuovo resolver che restituisce tutti i post nella tabella.

**Per aggiungere la tua mutazione**

1. Nella tua API, scegli la scheda **Schema**.

1. Nel riquadro **Schema**, modificare il tipo `Query` per aggiungere una nuova query `allPost` come segue:

   ```
   type Query {
       allPost(limit: Int, nextToken: String): PaginatedPosts!
       getPost(id: ID): Post
   }
   ```

1. Aggiungi un nuovo tipo `PaginationPosts`:

   ```
   type PaginatedPosts {
       posts: [Post!]!
       nextToken: String
   }
   ```

1. Scegli **Save Scheme (Salva schema)**.

1. **Nel **riquadro Resolver** a destra, trova il `allPost` campo appena creato nel `Query` tipo, quindi scegli Allega.** Crea un nuovo resolver con il seguente codice:

   ```
   import * as ddb from '@aws-appsync/utils/dynamodb';
   
   export function request(ctx) {
     const { limit = 20, nextToken } = ctx.arguments;
     return ddb.scan({ limit, nextToken });
   }
   
   export function response(ctx) {
     const { items: posts = [], nextToken } = ctx.result;
     return { posts, nextToken };
   }
   ```

   Il gestore delle richieste di questo resolver prevede due argomenti opzionali: 
   + `limit`- Speciifica il numero massimo di elementi da restituire in una singola chiamata.
   + `nextToken`- Utilizzato per recuperare il prossimo set di risultati (mostreremo da dove `nextToken` proviene il valore di in seguito).

1. Salva tutte le modifiche apportate al tuo resolver.

Per ulteriori informazioni sulla `Scan` richiesta, consulta la documentazione di riferimento di [Scan](https://docs.aws.amazon.com/appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-scan).

### Chiama l'API per scansionare tutti i post
<a name="call-api-scan"></a>

Ora che il resolver è stato configurato, AWS AppSync sa come tradurre una `allPost` query in entrata in un'operazione Amazon DynamoDB. `Scan` Puoi ora analizzare la tabella per recuperare tutti i post. Prima di provare, devi immettere nella tabella alcuni dati, perché hai eliminato tutti quelli usati finora.

**Per aggiungere e interrogare dati**

1. Nella tua API, scegli la scheda **Query**.

1. Nel riquadro **Query**, aggiungi la seguente mutazione:

   ```
   mutation addPost {
     post1: addPost(id:1 author: "AUTHORNAME" title: "A series of posts, Volume 1" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title }
     post2: addPost(id:2 author: "AUTHORNAME" title: "A series of posts, Volume 2" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title }
     post3: addPost(id:3 author: "AUTHORNAME" title: "A series of posts, Volume 3" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title }
     post4: addPost(id:4 author: "AUTHORNAME" title: "A series of posts, Volume 4" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title }
     post5: addPost(id:5 author: "AUTHORNAME" title: "A series of posts, Volume 5" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title }
     post6: addPost(id:6 author: "AUTHORNAME" title: "A series of posts, Volume 6" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title }
     post7: addPost(id:7 author: "AUTHORNAME" title: "A series of posts, Volume 7" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title }
     post8: addPost(id:8 author: "AUTHORNAME" title: "A series of posts, Volume 8" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title }
     post9: addPost(id:9 author: "AUTHORNAME" title: "A series of posts, Volume 9" content: "Some content" url: "https://aws.amazon.com/appsync/" ) { title }
   }
   ```

1. Scegli **Esegui** (il pulsante di riproduzione arancione). 

1. Analizziamo ora la tabella, restituendo cinque risultati per volta. Nel riquadro **Interrogazioni**, aggiungi la seguente interrogazione:

   ```
   query allPost {
     allPost(limit: 5) {
       posts {
         id
         title
       }
       nextToken
     }
   }
   ```

1. Scegli **Esegui** (il pulsante di riproduzione arancione), quindi scegli`allPost`.

   I primi cinque post dovrebbero apparire nel riquadro **Risultati** a destra del riquadro **Query**. La schermata visualizzata dovrebbe risultare simile a quella nell'immagine seguente:

   ```
   {
     "data": {
       "allPost": {
         "posts": [
           {
             "id": "5",
             "title": "A series of posts, Volume 5"
           },
           {
             "id": "1",
             "title": "A series of posts, Volume 1"
           },
           {
             "id": "6",
             "title": "A series of posts, Volume 6"
           },
           {
             "id": "9",
             "title": "A series of posts, Volume 9"
           },
           {
             "id": "7",
             "title": "A series of posts, Volume 7"
           }
         ],
         "nextToken": "<token>"
       }
     }
   }
   ```

1. Hai ricevuto cinque risultati e uno `nextToken` che puoi utilizzare per ottenere il prossimo set di risultati. Aggiornare la query `allPost` in modo da includere `nextToken` dal set precedente di risultati: 

   ```
   query allPost {
     allPost(
       limit: 5
       nextToken: "<token>"
     ) {
       posts {
         id
         author
       }
       nextToken
     }
   }
   ```

1. Scegli **Esegui** (il pulsante arancione di riproduzione), quindi scegli`allPost`.

   I quattro post rimanenti dovrebbero apparire nel riquadro **Risultati** a destra del riquadro **Interrogazioni**. Non c'è nessuno `nextToken` in questo set di risultati perché hai sfogliato tutti e nove i post senza che ne rimanga nessuno. La schermata visualizzata dovrebbe risultare simile a quella nell'immagine seguente:

   ```
   {
     "data": {
       "allPost": {
         "posts": [
           {
             "id": "2",
             "title": "A series of posts, Volume 2"
           },
           {
             "id": "3",
             "title": "A series of posts, Volume 3"
           },
           {
             "id": "4",
             "title": "A series of posts, Volume 4"
           },
           {
             "id": "8",
             "title": "A series of posts, Volume 8"
           }
         ],
         "nextToken": null
       }
     }
   }
   ```

## Configurazione di un allPostsBy Author resolver (Amazon DynamoDB Query)
<a name="configure-query"></a>

Oltre a scansionare Amazon DynamoDB per tutti i post, puoi anche interrogare Amazon DynamoDB per recuperare i post creati da un autore specifico. La tabella Amazon DynamoDB creata in precedenza contiene già `GlobalSecondaryIndex` una `author-index` chiamata che puoi usare con un'operazione Amazon DynamoDB per recuperare tutti i `Query` post creati da un autore specifico.

**Per aggiungere la tua query**

1. Nella tua API, scegli la scheda **Schema**.

1. Nel riquadro **Schema**, modificare il tipo `Query` per aggiungere una nuova query `allPostsByAuthor` come segue:

   ```
   type Query {
       allPostsByAuthor(author: String!, limit: Int, nextToken: String): PaginatedPosts!
       allPost(limit: Int, nextToken: String): PaginatedPosts!
       getPost(id: ID): Post
   }
   ```

   Tieni presente che utilizza lo stesso `PaginatedPosts` tipo che hai usato con la `allPost` query.

1. Scegli **Save Scheme (Salva schema)**.

1. **Nel **riquadro Resolver** a destra, individuate il `allPostsByAuthor` campo appena creato relativo al `Query` tipo, quindi scegliete Allega.** Crea un resolver utilizzando lo snippet seguente:

   ```
   import * as ddb from '@aws-appsync/utils/dynamodb';
   
   export function request(ctx) {
     const { limit = 20, nextToken, author } = ctx.arguments;
     return ddb.query({
       index: 'author-index',
       query: { author: { eq: author } },
       limit,
       nextToken,
     });
   }
   
   export function response(ctx) {
     const { items: posts = [], nextToken } = ctx.result;
     return { posts, nextToken };
   }
   ```

   Come il `allPost` resolver, questo resolver ha due argomenti opzionali:
   + `limit`- Speciifica il numero massimo di elementi da restituire in una singola chiamata.
   + `nextToken`- Recupera il successivo set di risultati (il valore di `nextToken` può essere ottenuto da una chiamata precedente).

1. Salva tutte le modifiche apportate al tuo resolver.

Per ulteriori informazioni sulla `Query` richiesta, consulta la documentazione di riferimento di [Query](https://docs.aws.amazon.com/appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-query).

### Chiama l'API per interrogare tutti i post per autore
<a name="call-api-query"></a>

Ora che il resolver è stato configurato, AWS AppSync sa come tradurre una `allPostsByAuthor` mutazione in entrata in un'operazione DynamoDB sull'indice. `Query` `author-index` Puoi ora eseguire una query sulla tabella per recuperare tutti i post di un autore specifico.

Prima di questo, tuttavia, riempiamo la tabella con altri post, perché finora tutti i post hanno lo stesso autore.

**Per aggiungere dati e interrogare**

1. Nella tua API, scegli la scheda **Query**.

1. Nel riquadro **Query**, aggiungi la seguente mutazione:

   ```
   mutation addPost {
     post1: addPost(id:10 author: "Nadia" title: "The cutest dog in the world" content: "So cute. So very, very cute." url: "https://aws.amazon.com/appsync/" ) { author, title }
     post2: addPost(id:11 author: "Nadia" title: "Did you know...?" content: "AppSync works offline?" url: "https://aws.amazon.com/appsync/" ) { author, title }
     post3: addPost(id:12 author: "Steve" title: "I like GraphQL" content: "It's great" url: "https://aws.amazon.com/appsync/" ) { author, title }
   }
   ```

1. Scegli **Esegui** (il pulsante arancione di riproduzione), quindi scegli. `addPost`

1. Esegui ora la query sulla tabella, per restituire tutti i post il cui autore è `Nadia`. Nel riquadro **Interrogazioni**, aggiungi la seguente interrogazione: 

   ```
   query allPostsByAuthor {
     allPostsByAuthor(author: "Nadia") {
       posts {
         id
         title
       }
       nextToken
     }
   }
   ```

1. Scegli **Esegui** (il pulsante di riproduzione arancione), quindi scegli`allPostsByAuthor`. Tutti i post creati da `Nadia` dovrebbero apparire nel riquadro **Risultati** a destra del riquadro **Query**. La schermata visualizzata dovrebbe risultare simile a quella nell'immagine seguente:

   ```
   {
     "data": {
       "allPostsByAuthor": {
         "posts": [
           {
             "id": "10",
             "title": "The cutest dog in the world"
           },
           {
             "id": "11",
             "title": "Did you know...?"
           }
         ],
         "nextToken": null
       }
     }
   }
   ```

1. La paginazione funziona per `Query` esattamente come per `Scan`. Ad esempio, cerchiamo tutti i post di `AUTHORNAME`, restituendone cinque per volta.

1. Nel riquadro Interrogazioni, aggiungi la seguente **query**: 

   ```
   query allPostsByAuthor {
     allPostsByAuthor(
       author: "AUTHORNAME"
       limit: 5
     ) {
       posts {
         id
         title
       }
       nextToken
     }
   }
   ```

1. Scegli **Esegui** (il pulsante di riproduzione arancione), quindi scegli`allPostsByAuthor`. Tutti i post creati da `AUTHORNAME` dovrebbero apparire nel riquadro **Risultati** a destra del riquadro **Query**. La schermata visualizzata dovrebbe risultare simile a quella nell'immagine seguente:

   ```
   {
     "data": {
       "allPostsByAuthor": {
         "posts": [
           {
             "id": "6",
             "title": "A series of posts, Volume 6"
           },
           {
             "id": "4",
             "title": "A series of posts, Volume 4"
           },
           {
             "id": "2",
             "title": "A series of posts, Volume 2"
           },
           {
             "id": "7",
             "title": "A series of posts, Volume 7"
           },
           {
             "id": "1",
             "title": "A series of posts, Volume 1"
           }
         ],
         "nextToken": "<token>"
       }
     }
   }
   ```

1. Aggiornare l'argomento `nextToken` con il valore restituito dalla query precedente, come segue:

   ```
   query allPostsByAuthor {
     allPostsByAuthor(
       author: "AUTHORNAME"
       limit: 5
       nextToken: "<token>"
     ) {
       posts {
         id
         title
       }
       nextToken
     }
   }
   ```

1. Scegli **Esegui** (il pulsante arancione di riproduzione), quindi scegli. `allPostsByAuthor` I post rimanenti creati da `AUTHORNAME` dovrebbero apparire nel riquadro **Risultati** a destra del riquadro **Query**. La schermata visualizzata dovrebbe risultare simile a quella nell'immagine seguente:

   ```
   {
     "data": {
       "allPostsByAuthor": {
         "posts": [
           {
             "id": "8",
             "title": "A series of posts, Volume 8"
           },
           {
             "id": "5",
             "title": "A series of posts, Volume 5"
           },
           {
             "id": "3",
             "title": "A series of posts, Volume 3"
           },
           {
             "id": "9",
             "title": "A series of posts, Volume 9"
           }
         ],
         "nextToken": null
       }
     }
   }
   ```

## Utilizzo dei set
<a name="using-sets"></a>

Fino a questo punto, il `Post` tipo era un key/value oggetto piatto. Puoi anche modellare oggetti complessi con il tuo resolver, come set, elenchi e mappe. Aggiorniamo ora il tipo `Post` perché includa tag. Un post può avere zero o più tag, che vengono archiviati in DynamoDB come set di stringhe. Dobbiamo anche configurare alcune mutazioni per aggiungere e rimuovere tag e una query per analizzare i post con un tag specifico.

**Per configurare i tuoi dati**

1. Nella tua API, scegli la scheda **Schema**. 

1. Nel riquadro **Schema**, modificare il tipo `Post` per aggiungere un nuovo campo `tags` come segue:

   ```
   type Post {
     id: ID!
     author: String
     title: String
     content: String
     url: String
     ups: Int!
     downs: Int!
     version: Int!
     tags: [String!]
   }
   ```

1. Nel riquadro **Schema**, modificare il tipo `Query` per aggiungere una nuova query `allPostsByTag` come segue:

   ```
   type Query {
     allPostsByTag(tag: String!, limit: Int, nextToken: String): PaginatedPosts!
     allPostsByAuthor(author: String!, limit: Int, nextToken: String): PaginatedPosts!
     allPost(limit: Int, nextToken: String): PaginatedPosts!
     getPost(id: ID): Post
   }
   ```

1. Nel riquadro **Schema**, modifica il `Mutation` tipo per aggiungere nuove `addTag` e `removeTag` mutazioni come segue:

   ```
   type Mutation {
     addTag(id: ID!, tag: String!): Post
     removeTag(id: ID!, tag: String!): Post
     deletePost(id: ID!, expectedVersion: Int): Post
     upvotePost(id: ID!): Post
     downvotePost(id: ID!): Post
     updatePost(
       id: ID!,
       author: String,
       title: String,
       content: String,
       url: String,
       expectedVersion: Int!
     ): Post
     addPost(
       author: String!,
       title: String!,
       content: String!,
       url: String!
     ): Post!
   }
   ```

1. Scegli **Save Scheme (Salva schema)**.

1. **Nel **riquadro Resolver** a destra, individuate il `allPostsByTag` campo appena creato relativo al `Query` tipo, quindi scegliete Allega.** Crea il tuo resolver usando lo snippet qui sotto:

   ```
   import * as ddb from '@aws-appsync/utils/dynamodb';
   
   export function request(ctx) {
     const { limit = 20, nextToken, tag } = ctx.arguments;
     return ddb.scan({ limit, nextToken, filter: { tags: { contains: tag } } });
   }
   
   export function response(ctx) {
     const { items: posts = [], nextToken } = ctx.result;
     return { posts, nextToken };
   }
   ```

1. Salva tutte le modifiche che hai apportato al tuo resolver.

1. Ora, fai lo stesso per il `Mutation` campo `addTag` usando lo snippet qui sotto:
**Nota**  
Sebbene le utilità DynamoDB attualmente non supportino le operazioni sui set, puoi comunque interagire con i set creando tu stesso la richiesta.

   ```
   import { util } from '@aws-appsync/utils'
   
   export function request(ctx) {
   	const { id, tag } = ctx.arguments
   	const expressionValues = util.dynamodb.toMapValues({ ':plusOne': 1 })
   	expressionValues[':tags'] = util.dynamodb.toStringSet([tag])
   
   	return {
   		operation: 'UpdateItem',
   		key: util.dynamodb.toMapValues({ id }),
   		update: {
   			expression: `ADD tags :tags, version :plusOne`,
   			expressionValues,
   		},
   	}
   }
   
   export const response = (ctx) => ctx.result
   ```

1. Salva tutte le modifiche apportate al tuo resolver.

1. Ripeti l'operazione ancora una volta per il `Mutation` campo `removeTag` utilizzando lo snippet seguente:

   ```
   import { util } from '@aws-appsync/utils';
   	
   export function request(ctx) {
   	  const { id, tag } = ctx.arguments;
   	  const expressionValues = util.dynamodb.toMapValues({ ':plusOne': 1 });
   	  expressionValues[':tags'] = util.dynamodb.toStringSet([tag]);
   	
   	  return {
   	    operation: 'UpdateItem',
   	    key: util.dynamodb.toMapValues({ id }),
   	    update: {
   	      expression: `DELETE tags :tags ADD version :plusOne`,
   	      expressionValues,
   	    },
   	  };
   	}
   	
   	export const response = (ctx) => ctx.resultexport
   ```

1. Salva tutte le modifiche apportate al tuo resolver.

### Chiamata dell'API per usare tag
<a name="call-api-tags"></a>

Ora che hai configurato i resolver, AWS AppSync sa come tradurre le richieste in entrata `addTag` e le richieste `allPostsByTag` in DynamoDB e nelle operazioni. `removeTag` `UpdateItem` `Scan` Per provare, selezioniamo uno dei post creati prima. Ad esempio, è possibile utilizzare un post redatto dall'utente `Nadia`.

**Per usare i tag**

1. Nella tua API, scegli la scheda **Query**.

1. Nel riquadro **Query**, aggiungi la seguente query:

   ```
   query allPostsByAuthor {
     allPostsByAuthor(
       author: "Nadia"
     ) {
       posts {
         id
         title
       }
       nextToken
     }
   }
   ```

1. Scegli **Esegui** (il pulsante di riproduzione arancione), quindi scegli`allPostsByAuthor`.

1. Tutti i post di Nadia dovrebbero apparire nel riquadro **Risultati** a destra del riquadro **Query**. La schermata visualizzata dovrebbe risultare simile a quella nell'immagine seguente:

   ```
   {
     "data": {
       "allPostsByAuthor": {
         "posts": [
           {
             "id": "10",
             "title": "The cutest dog in the world"
           },
           {
             "id": "11",
             "title": "Did you known...?"
           }
         ],
         "nextToken": null
       }
     }
   }
   ```

1. Usiamo quello con il titolo *Il cane più carino del mondo*. Registralo `id` perché lo userai più tardi. Ora proviamo ad aggiungere un `dog` tag.

1. Nel riquadro **Query**, aggiungi la seguente mutazione. Dovremo anche aggiornare l'argomento `id` sul valore che abbiamo annotato in precedenza.

   ```
   mutation addTag {
     addTag(id:10 tag: "dog") {
       id
       title
       tags
     }
   }
   ```

1. Scegli **Esegui** (il pulsante arancione di riproduzione), quindi scegli. `addTag` Il post viene aggiornato con il nuovo tag:

   ```
   {
     "data": {
       "addTag": {
         "id": "10",
         "title": "The cutest dog in the world",
         "tags": [
           "dog"
         ]
       }
     }
   }
   ```

1. Puoi aggiungere altri tag. Aggiorna la mutazione per cambiare l'`tag`argomento in`puppy`:

   ```
   mutation addTag {
     addTag(id:10 tag: "puppy") {
       id
       title
       tags
     }
   }
   ```

1. Scegli **Esegui** (il pulsante arancione di riproduzione), quindi scegli`addTag`. Il post viene aggiornato con il nuovo tag:

   ```
   {
     "data": {
       "addTag": {
         "id": "10",
         "title": "The cutest dog in the world",
         "tags": [
           "dog",
           "puppy"
         ]
       }
     }
   }
   ```

1. Puoi anche eliminare i tag. Nel riquadro **Query**, aggiungi la seguente mutazione. Dovrai anche aggiornare l'`id`argomento al valore annotato in precedenza:

   ```
   mutation removeTag {
     removeTag(id:10 tag: "puppy") {
       id
       title
       tags
     }
   }
   ```

1. Scegli **Esegui** (il pulsante arancione di riproduzione), quindi scegli`removeTag`. Il post viene aggiornato e il tag `puppy` viene eliminato.

   ```
   {
     "data": {
       "addTag": {
         "id": "10",
         "title": "The cutest dog in the world",
         "tags": [
           "dog"
         ]
       }
     }
   }
   ```

1. Puoi anche cercare tutti i post che hanno un tag. Nel riquadro **Interrogazioni**, aggiungi la seguente query: 

   ```
   query allPostsByTag {
     allPostsByTag(tag: "dog") {
       posts {
         id
         title
         tags
       }
       nextToken
     }
   }
   ```

1. Scegli **Esegui** (il pulsante di riproduzione arancione), quindi scegli`allPostsByTag`. Vengono restituiti tutti i post con il tag `dog` come segue:

   ```
   {
     "data": {
       "allPostsByTag": {
         "posts": [
           {
             "id": "10",
             "title": "The cutest dog in the world",
             "tags": [
               "dog",
               "puppy"
             ]
           }
         ],
         "nextToken": null
       }
     }
   }
   ```

## Conclusioni
<a name="conclusion-dynamodb-tutorial-js"></a>

In questo tutorial, hai creato un'API che ti consente di manipolare `Post` oggetti in DynamoDB AWS AppSync utilizzando GraphQL. 

Per eseguire la pulizia, puoi eliminare l'API AWS AppSync GraphQL dalla console. 

**Per eliminare il ruolo associato alla tabella DynamoDB, seleziona l'origine dati nella tabella Fonti **dati e fai** clic su modifica.** Annota il valore del ruolo in **Crea o usa un ruolo esistente**. Vai alla console IAM per eliminare il ruolo.

Per eliminare la tabella DynamoDB, fai clic sul nome della tabella nell'elenco delle fonti di dati. Si accede alla console DynamoDB dove è possibile eliminare la tabella. 

# Utilizzo dei AWS Lambda resolver in AWS AppSync
<a name="tutorial-lambda-resolvers-js"></a>

Puoi usare AWS Lambda with AWS AppSync per risolvere qualsiasi campo GraphQL. Ad esempio, una query GraphQL potrebbe inviare una chiamata a un'istanza Amazon Relational Database Service (Amazon RDS) e una mutazione GraphQL potrebbe scrivere su un flusso Amazon Kinesis. In questa sezione, ti mostreremo come scrivere una funzione Lambda che esegue la logica aziendale basata sull'invocazione di un'operazione sul campo GraphQL.

## Powertools per AWS Lambda
<a name="powertools-graphql"></a>

Il gestore di eventi Powertools for AWS Lambda GraphQL semplifica il routing e l'elaborazione degli eventi GraphQL nelle funzioni Lambda. È disponibile per Python e Typescript. Per saperne di più sul gestore di eventi dell'API GraphQL, consulta Powertools per la AWS Lambda documentazione, consulta i seguenti riferimenti.
+ [Powertools per il gestore di eventi AWS Lambda GraphQL (Python)](https://docs.aws.amazon.com/powertools/python/latest/core/event_handler/appsync/)
+ [Powertools per il gestore di eventi AWS Lambda GraphQL (Typescript)](https://docs.aws.amazon.com/powertools/typescript/latest/features/event-handler/appsync-graphql/) 

## Creazione di una funzione Lambda
<a name="create-a-lam-function-js"></a>

L'esempio seguente mostra una funzione Lambda scritta in `Node.js` (runtime: Node.js 18.x) che esegue diverse operazioni sui post del blog come parte di un'applicazione per post di blog. Nota che il codice deve essere salvato in un nome di file con estensione.mis.

```
export const handler = async (event) => {
console.log('Received event {}', JSON.stringify(event, 3))

  const posts = {
1: { id: '1', title: 'First book', author: 'Author1', url: 'https://amazon.com/', content: 'SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1', ups: '100', downs: '10', },
    2: { id: '2', title: 'Second book', author: 'Author2', url: 'https://amazon.com', content: 'SAMPLE TEXT AUTHOR 2 SAMPLE TEXT AUTHOR 2 SAMPLE TEXT', ups: '100', downs: '10', },
    3: { id: '3', title: 'Third book', author: 'Author3', url: null, content: null, ups: null, downs: null },
    4: { id: '4', title: 'Fourth book', author: 'Author4', url: 'https://www.amazon.com/', content: 'SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4', ups: '1000', downs: '0', },
    5: { id: '5', title: 'Fifth book', author: 'Author5', url: 'https://www.amazon.com/', content: 'SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT', ups: '50', downs: '0', },
  }

  const relatedPosts = {
1: [posts['4']],
    2: [posts['3'], posts['5']],
    3: [posts['2'], posts['1']],
    4: [posts['2'], posts['1']],
    5: [],
  }

  console.log('Got an Invoke Request.')
  let result
  switch (event.field) {
case 'getPost':
      return posts[event.arguments.id]
    case 'allPosts':
      return Object.values(posts)
    case 'addPost':
      // return the arguments back
return event.arguments
    case 'addPostErrorWithData':
      result = posts[event.arguments.id]
      // attached additional error information to the post
      result.errorMessage = 'Error with the mutation, data has changed'
      result.errorType = 'MUTATION_ERROR'
return result
    case 'relatedPosts':
      return relatedPosts[event.source.id]
    default:
      throw new Error('Unknown field, unable to resolve ' + event.field)
  }
}
```

Questa funzione Lambda recupera un post per ID, aggiunge un post, recupera un elenco di post e recupera i post correlati per un determinato post. 

**Nota**  
La funzione Lambda utilizza l'`switch`istruzione on `event.field` per determinare quale campo è attualmente in fase di risoluzione.

Crea questa funzione Lambda utilizzando la console di AWS gestione.

## Configurare un'origine dati per Lambda
<a name="configure-data-source-for-lamlong-js"></a>

**Dopo aver creato la funzione Lambda, accedi all'API GraphQL nella AWS AppSync console, quindi scegli la scheda Data Sources.**

**Scegli **Crea origine dati**, inserisci un **nome di origine dati descrittivo** (ad esempio**Lambda**), quindi per **Tipo di origine dati**, scegli AWS Lambda funzione.** Per **Regione**, scegli la stessa regione della tua funzione. Per **Function ARN**, scegli l'Amazon Resource Name (ARN) della tua funzione Lambda.

Dopo aver scelto la funzione Lambda, puoi creare un nuovo ruolo AWS Identity and Access Management (IAM) (per il quale AWS AppSync assegna le autorizzazioni appropriate) o scegliere un ruolo esistente con la seguente politica in linea:

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

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "lambda:InvokeFunction"
            ],
            "Resource": "arn:aws:lambda:us-east-1:111122223333:function:LAMBDA_FUNCTION"
        }
    ]
}
```

------

È inoltre necessario impostare una relazione di fiducia con AWS AppSync per il ruolo IAM nel modo seguente:

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

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "appsync.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
```

------

## Creare uno schema GraphQL
<a name="creating-a-graphql-schema-js"></a>

Ora che l'origine dati è connessa alla funzione Lambda, crea uno schema GraphQL.

Dall'editor di schemi nella AWS AppSync console, assicurati che lo schema corrisponda allo schema seguente:

```
schema {
    query: Query
    mutation: Mutation
}
type Query {
    getPost(id:ID!): Post
    allPosts: [Post]
}
type Mutation {
    addPost(id: ID!, author: String!, title: String, content: String, url: String): Post!
}
type Post {
    id: ID!
    author: String!
    title: String
    content: String
    url: String
    ups: Int
    downs: Int
    relatedPosts: [Post]
}
```

## Configura i resolver
<a name="configuring-resolvers-js"></a>

Ora che hai registrato un'origine dati Lambda e uno schema GraphQL valido, puoi connettere i campi GraphQL all'origine dati Lambda utilizzando i resolver.

Creerai un resolver che utilizza il runtime AWS AppSync JavaScript (`APPSYNC_JS`) e interagirà con le tue funzioni Lambda. Per ulteriori informazioni sulla scrittura di AWS AppSync resolver e funzioni con JavaScript, consulta le funzionalità di [JavaScript runtime](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference-js.html) per resolver e funzioni.

Per ulteriori informazioni sui modelli di mappatura Lambda, consulta il riferimento alla [JavaScript funzione resolver](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-lambda-js.html) per Lambda.

In questo passaggio, si collega un resolver alla funzione Lambda per i seguenti campi:`getPost(id:ID!): Post`,, `allPosts: [Post]` e. `addPost(id: ID!, author: String!, title: String, content: String, url: String): Post!` `Post.relatedPosts: [Post]` **Dall'editor di **schema** della AWS AppSync console, nel riquadro **Resolver, scegli Allega** accanto al campo.** `getPost(id:ID!): Post` Scegli la tua fonte di dati Lambda. Quindi, fornisci il seguente codice:

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

export function request(ctx) {
  const {source, args} = ctx
  return {
    operation: 'Invoke',
    payload: { field: ctx.info.fieldName, arguments: args, source },
  };
}

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

Questo codice resolver passa il nome del campo, l'elenco di argomenti e il contesto relativo all'oggetto sorgente alla funzione Lambda quando viene richiamata. Scegli **Save** (Salva).

Il primo resolver è stato ora collegato con successo. Ripetere questa operazione per i campi rimanenti. 

## Testa la tua API GraphQL
<a name="testing-your-graphql-api-js"></a>

Ora che la funzione Lambda è connessa ai resolver GraphQL, puoi eseguire alcune mutazioni e query usando la console o un'applicazione client.

Sul lato sinistro della AWS AppSync console, scegli **Queries**, quindi incolla il codice seguente:

### addPost Mutation
<a name="addpost-mutation-js"></a>

```
mutation AddPost {
    addPost(
        id: 6
        author: "Author6"
        title: "Sixth book"
        url: "https://www.amazon.com/"
        content: "This is the book is a tutorial for using GraphQL with AWS AppSync."
    ) {
        id
        author
        title
        content
        url
        ups
        downs
    }
}
```

### getPost Query
<a name="getpost-query-js"></a>

```
query GetPost {
    getPost(id: "2") {
        id
        author
        title
        content
        url
        ups
        downs
    }
}
```

### allPosts Query
<a name="allposts-query-js"></a>

```
query AllPosts {
    allPosts {
        id
        author
        title
        content
        url
        ups
        downs
        relatedPosts {
            id
            title
        }
    }
}
```

## Errori di restituzione
<a name="returning-errors-js"></a>

Qualsiasi risoluzione di campo può causare un errore. Con AWS AppSync, puoi generare errori dalle seguenti fonti:
+ Gestore di risposte Resolver
+ funzione Lambda

### Dal gestore di risposte del resolver
<a name="from-the-resolver-response-handler-js"></a>

Per generare errori intenzionali, è possibile utilizzare il metodo di utilità. `util.error` Richiede un argomento an `errorMessage``errorType`, un e un `data` valore opzionale. Il valore `data` è utile per restituire dati aggiuntivi al client quando è stato generato un errore. L'oggetto `data` verrà aggiunto a `errors` nella risposta finale di GraphQL.

L'esempio seguente mostra come usarlo nel gestore di risposte del `Post.relatedPosts: [Post]` resolver.

```
// the Post.relatedPosts response handler
export function response(ctx) {
    util.error("Failed to fetch relatedPosts", "LambdaFailure", ctx.result)
    return ctx.result;
}
```

Ciò restituirà una risposta di GraphQL simile alla seguente:

```
{
    "data": {
        "allPosts": [
            {
                "id": "2",
                "title": "Second book",
                "relatedPosts": null
            },
            ...
        ]
    },
    "errors": [
        {
            "path": [
                "allPosts",
                0,
                "relatedPosts"
            ],
            "errorType": "LambdaFailure",
            "locations": [
                {
                    "line": 5,
                    "column": 5
                }
            ],
            "message": "Failed to fetch relatedPosts",
            "data": [
                {
                  "id": "2",
                  "title": "Second book"
                },
                {
                  "id": "1",
                  "title": "First book"
                }
            ]
        }
    ]
}
```

Dove `allPosts[0].relatedPosts` è *null* a causa dell'errore e `errorMessage`, `errorType` e `data` sono presenti nell'oggetto `data.errors[0]`.

### Dalla funzione Lambda
<a name="from-the-lam-function-js"></a>

AWS AppSync comprende anche gli errori generati dalla funzione Lambda. Il modello di programmazione Lambda consente di generare errori *gestiti*. Se la funzione Lambda genera un errore, AWS AppSync non riesce a risolvere il campo corrente. Nella risposta viene impostato solo il messaggio di errore restituito da Lambda. Attualmente, non è possibile restituire dati estranei al client generando un errore dalla funzione Lambda. 

**Nota**  
Se la funzione Lambda genera un errore *non gestito*, AWS AppSync utilizza il messaggio di errore impostato da Lambda.

La funzione Lambda seguente genera un errore:

```
export const handler = async (event) => {
  console.log('Received event {}', JSON.stringify(event, 3))
  throw new Error('I always fail.')
}
```

L'errore viene ricevuto nel gestore delle risposte. Puoi rispedirlo nella risposta GraphQL aggiungendo l'errore alla risposta con. `util.appendError` Per fare ciò, modifica il gestore AWS AppSync della risposta alla funzione in questo modo:

```
// the lambdaInvoke response handler
export function response(ctx) {
  const { error, result } = ctx;
  if (error) {
    util.appendError(error.message, error.type, result);
  }
  return result;
}
```

Ciò restituirà una risposta di GraphQL simile alla seguente:

```
{
  "data": {
    "allPosts": null
  },
  "errors": [
    {
      "path": [
        "allPosts"
      ],
      "data": null,
      "errorType": "Lambda:Unhandled",
      "errorInfo": null,
      "locations": [
        {
          "line": 2,
          "column": 3,
          "sourceName": null
        }
      ],
      "message": "I fail. always"
    }
  ]
}
```

## Caso d'uso avanzato: Batching
<a name="advanced-use-case-batching-js"></a>

La funzione Lambda in questo esempio ha un `relatedPosts` campo che restituisce un elenco di post correlati per un determinato post. Nelle query di esempio, l'invocazione del `allPosts` campo dalla funzione Lambda restituisce cinque post. Poiché abbiamo specificato che vogliamo risolvere anche `relatedPosts` per ogni post restituito, l'operazione `relatedPosts` sul campo viene richiamata cinque volte.

```
query {
    allPosts {   // 1 Lambda invocation - yields 5 Posts
        id
        author
        title
        content
        url
        ups
        downs
        relatedPosts {   // 5 Lambda invocations - each yields 5 posts
            id
            title
        }
    }
}
```

Anche se questo potrebbe non sembrare importante in questo esempio specifico, questo eccesso di recupero aggravato può compromettere rapidamente l'applicazione.

Se, ad esempio, dovessimo recuperare di nuovo `relatedPosts` sui `Posts` correlati restituiti nella stessa query, il numero di chiamate aumenterebbe notevolmente.

```
query {
    allPosts {   // 1 Lambda invocation - yields 5 Posts
        id
        author
        title
        content
        url
        ups
        downs
        relatedPosts {   // 5 Lambda invocations - each yield 5 posts = 5 x 5 Posts
            id
            title
            relatedPosts {  // 5 x 5 Lambda invocations - each yield 5 posts = 25 x 5 Posts
                id
                title
                author
            }
        }
    }
}
```

In questa query relativamente semplice, AWS AppSync richiamerebbe la funzione Lambda 1 \$1 5 \$1 25 = 31 volte.

Si tratta di una sfida piuttosto comune a cui si fa spesso riferimento come problema N\$11, (nel nostro caso, N = 5) che può determinare un aumento della latenza e dei costi dell'applicazione.

Un approccio alla soluzione di questo problema consiste nel raggruppare in batch richieste del resolver di campo simili. In questo esempio, invece di fare in modo che la funzione Lambda risolva un elenco di post correlati per un singolo post, potrebbe invece risolvere un elenco di post correlati per un determinato batch di post.

Per dimostrarlo, aggiorniamo il resolver per `relatedPosts` gestire il batching.

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

export function request(ctx) {
  const {source, args} = ctx
  return {
    operation: ctx.info.fieldName === 'relatedPosts' ? 'BatchInvoke' : 'Invoke',
    payload: { field: ctx.info.fieldName, arguments: args, source },
  };
}

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

Il codice ora modifica l'operazione da `Invoke` a `BatchInvoke` quando è in `fieldName` corso la risoluzione. `relatedPosts` Ora, abilita il batching sulla funzione nella sezione **Configura batch**. Imposta la dimensione massima di batch impostata su. `5` Scegli **Save** (Salva).

Con questa modifica, durante la risoluzione`relatedPosts`, la funzione Lambda riceve quanto segue come input:

```
[
    {
        "field": "relatedPosts",
        "source": {
            "id": 1
        }
    },
    {
        "field": "relatedPosts",
        "source": {
            "id": 2
        }
    },
    ...
]
```

Quando `BatchInvoke` è specificata nella richiesta, la funzione Lambda riceve un elenco di richieste e restituisce un elenco di risultati.

In particolare, l'elenco dei risultati deve corrispondere alla dimensione e all'ordine delle voci del payload della richiesta in modo che AWS AppSync possa corrispondere ai risultati di conseguenza.

In questo esempio di batch, la funzione Lambda restituisce un batch di risultati come segue:

```
[
    [{"id":"2","title":"Second book"}, {"id":"3","title":"Third book"}],   // relatedPosts for id=1
    [{"id":"3","title":"Third book"}]                                     // relatedPosts for id=2
]
```

Puoi aggiornare il codice Lambda per gestire il batch per: `relatedPosts`

```
export const handler = async (event) => {
  console.log('Received event {}', JSON.stringify(event, 3))
  //throw new Error('I fail. always')

  const posts = {
    1: { id: '1', title: 'First book', author: 'Author1', url: 'https://amazon.com/', content: 'SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1', ups: '100', downs: '10', },
    2: { id: '2', title: 'Second book', author: 'Author2', url: 'https://amazon.com', content: 'SAMPLE TEXT AUTHOR 2 SAMPLE TEXT AUTHOR 2 SAMPLE TEXT', ups: '100', downs: '10', },
    3: { id: '3', title: 'Third book', author: 'Author3', url: null, content: null, ups: null, downs: null },
    4: { id: '4', title: 'Fourth book', author: 'Author4', url: 'https://www.amazon.com/', content: 'SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4', ups: '1000', downs: '0', },
    5: { id: '5', title: 'Fifth book', author: 'Author5', url: 'https://www.amazon.com/', content: 'SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT', ups: '50', downs: '0', },
  }

  const relatedPosts = {
    1: [posts['4']],
    2: [posts['3'], posts['5']],
    3: [posts['2'], posts['1']],
    4: [posts['2'], posts['1']],
    5: [],
  }
  
  if (!event.field && event.length){
    console.log(`Got a BatchInvoke Request. The payload has ${event.length} items to resolve.`);
    return event.map(e => relatedPosts[e.source.id])
  }

  console.log('Got an Invoke Request.')
  let result
  switch (event.field) {
    case 'getPost':
      return posts[event.arguments.id]
    case 'allPosts':
      return Object.values(posts)
    case 'addPost':
      // return the arguments back
      return event.arguments
    case 'addPostErrorWithData':
      result = posts[event.arguments.id]
      // attached additional error information to the post
      result.errorMessage = 'Error with the mutation, data has changed'
      result.errorType = 'MUTATION_ERROR'
      return result
    case 'relatedPosts':
      return relatedPosts[event.source.id]
    default:
      throw new Error('Unknown field, unable to resolve ' + event.field)
  }
}
```

### Restituzione di errori individuali
<a name="returning-individual-errors-js"></a>

Gli esempi precedenti mostrano che è possibile restituire un singolo errore dalla funzione Lambda o generare un errore dal gestore delle risposte. Per le chiamate in batch, la generazione di un errore dalla funzione Lambda contrassegna un intero batch come fallito. Questo potrebbe essere accettabile per scenari specifici in cui si verifica un errore irreversibile, ad esempio una connessione non riuscita a un data store. Tuttavia, nei casi in cui alcuni elementi del batch abbiano esito positivo e altri falliscano, è possibile restituire sia errori che dati validi. Poiché AWS AppSync richiede la risposta in batch agli elementi dell'elenco che corrispondono alla dimensione originale del batch, è necessario definire una struttura di dati in grado di differenziare i dati validi da un errore.

*Ad esempio, se si prevede che la funzione Lambda restituisca un batch di post correlati, è possibile scegliere di restituire un elenco di `Response` oggetti in cui ogni oggetto contiene *dati* opzionali, campi ErrorMessage ed *ErrorType*.* La presenza del campo *errorMessage* indica un errore.

Il codice seguente mostra come aggiornare la funzione Lambda:

```
export const handler = async (event) => {
console.log('Received event {}', JSON.stringify(event, 3))
  // throw new Error('I fail. always')
const posts = {
1: { id: '1', title: 'First book', author: 'Author1', url: 'https://amazon.com/', content: 'SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1', ups: '100', downs: '10', },
    2: { id: '2', title: 'Second book', author: 'Author2', url: 'https://amazon.com', content: 'SAMPLE TEXT AUTHOR 2 SAMPLE TEXT AUTHOR 2 SAMPLE TEXT', ups: '100', downs: '10', },
    3: { id: '3', title: 'Third book', author: 'Author3', url: null, content: null, ups: null, downs: null },
    4: { id: '4', title: 'Fourth book', author: 'Author4', url: 'https://www.amazon.com/', content: 'SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4', ups: '1000', downs: '0', },
    5: { id: '5', title: 'Fifth book', author: 'Author5', url: 'https://www.amazon.com/', content: 'SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT', ups: '50', downs: '0', },
  }

  const relatedPosts = {
1: [posts['4']],
    2: [posts['3'], posts['5']],
    3: [posts['2'], posts['1']],
    4: [posts['2'], posts['1']],
    5: [],
  }
  
  if (!event.field && event.length){
console.log(`Got a BatchInvoke Request. The payload has ${event.length} items to resolve.`);
    return event.map(e => {
// return an error for post 2
if (e.source.id === '2') {
return { 'data': null, 'errorMessage': 'Error Happened', 'errorType': 'ERROR' }
      }
      return {data: relatedPosts[e.source.id]}
      })
  }

  console.log('Got an Invoke Request.')
  let result
  switch (event.field) {
case 'getPost':
      return posts[event.arguments.id]
    case 'allPosts':
      return Object.values(posts)
    case 'addPost':
      // return the arguments back
return event.arguments
    case 'addPostErrorWithData':
      result = posts[event.arguments.id]
      // attached additional error information to the post
      result.errorMessage = 'Error with the mutation, data has changed'
      result.errorType = 'MUTATION_ERROR'
return result
    case 'relatedPosts':
      return relatedPosts[event.source.id]
    default:
      throw new Error('Unknown field, unable to resolve ' + event.field)
  }
}
```

Aggiorna il codice del `relatedPosts` resolver:

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

export function request(ctx) {
  const {source, args} = ctx
  return {
    operation: ctx.info.fieldName === 'relatedPosts' ? 'BatchInvoke' : 'Invoke',
    payload: { field: ctx.info.fieldName, arguments: args, source },
  };
}

export function response(ctx) {
  const { error, result } = ctx;
  if (error) {
    util.appendError(error.message, error.type, result);
  } else if (result.errorMessage) {
    util.appendError(result.errorMessage, result.errorType, result.data)
  } else if (ctx.info.fieldName === 'relatedPosts') {
      return result.data
  } else {
      return result
  }
}
```

Il gestore delle risposte ora controlla gli errori restituiti dalla funzione Lambda `Invoke` sulle operazioni, controlla gli errori restituiti per i singoli elementi `BatchInvoke` per le operazioni e infine controlla il. `fieldName` Perché`relatedPosts`, la funzione restituisce. `result.data` Per tutti gli altri campi, la funzione si limita a restituire`result`. Ad esempio, vedi la query seguente:

```
query AllPosts {
  allPosts {
    id
    title
    content
    url
    ups
    downs
    relatedPosts {
      id
    }
    author
  }
}
```

Questa query restituisce una risposta GraphQL simile alla seguente:

```
{
  "data": {
    "allPosts": [
      {
        "id": "1",
        "relatedPosts": [
          {
            "id": "4"
          }
        ]
      },
      {
        "id": "2",
        "relatedPosts": null
      },
      {
        "id": "3",
        "relatedPosts": [
          {
            "id": "2"
          },
          {
            "id": "1"
          }
        ]
      },
      {
        "id": "4",
        "relatedPosts": [
          {
            "id": "2"
          },
          {
            "id": "1"
          }
        ]
      },
      {
        "id": "5",
        "relatedPosts": []
      }
    ]
  },
  "errors": [
    {
      "path": [
        "allPosts",
        1,
        "relatedPosts"
      ],
      "data": null,
      "errorType": "ERROR",
      "errorInfo": null,
      "locations": [
        {
          "line": 4,
          "column": 5,
          "sourceName": null
        }
      ],
      "message": "Error Happened"
    }
  ]
}
```

### Configurazione della dimensione massima di batch
<a name="configure-max-batch-size-js"></a>

Per configurare la dimensione massima di batch su un resolver, utilizzate il seguente comando in (): AWS Command Line Interface AWS CLI

```
$ aws appsync create-resolver --api-id <api-id> --type-name Query --field-name relatedPosts \
 --code "<code-goes-here>" \
 --runtime name=APPSYNC_JS,runtimeVersion=1.0.0 \
 --data-source-name "<lambda-datasource>" \ 
 --max-batch-size X
```

**Nota**  
Quando si fornisce un modello di mappatura delle richieste, è necessario utilizzare l'`BatchInvoke`operazione per utilizzare il batch.

# Utilizzo di resolver locali in AWS AppSync
<a name="tutorial-local-resolvers-js"></a>

AWS AppSync consente di utilizzare fonti di dati supportate (AWS Lambda Amazon DynamoDB o OpenSearch Amazon Service) per eseguire varie operazioni. In alcuni scenari, tuttavia, una chiamata a un'origine dati supportata può non essere necessaria.

È in queste situazioni che il resolver locale risulta utile. Invece di chiamare una fonte di dati remota, il resolver locale **inoltrerà** semplicemente il risultato del gestore della richiesta al gestore della risposta. La risoluzione del campo rimarrà in AWS AppSync.

I resolver locali sono utili in una miriade di situazioni. Quello più comune è la pubblicazione di notifiche senza attivare una chiamata a un'origine dati. Per dimostrare questo caso d'uso, creiamo un'applicazione pub/sub in cui gli utenti possano pubblicare e iscriversi ai messaggi. In questo esempio vengono usate le *sottoscrizioni*. Quindi, se non hai familiarità con le *sottoscrizioni*, puoi seguire il tutorial [Dati in tempo reale](aws-appsync-real-time-data.md).

## Creazione dell'app pub/sub
<a name="create-the-pub-sub-application-js"></a>

Innanzitutto, crea un'API GraphQL vuota scegliendo l'opzione **Design from scratch** e configurando i dettagli opzionali durante la creazione dell'API GraphQL.

Nella nostra applicazione pub/sub, i clienti possono iscriversi e pubblicare messaggi. Ogni messaggio pubblicato include un nome e dei dati. Aggiungi questo allo schema:

```
type Channel {
	name: String!
	data: AWSJSON!
}

type Mutation {
	publish(name: String!, data: AWSJSON!): Channel
}

type Query {
	getChannel: Channel
}

type Subscription {
	subscribe(name: String!): Channel
		@aws_subscribe(mutations: ["publish"])
}
```

Quindi, colleghiamo un resolver al `Mutation.publish` campo. **Nel **riquadro Resolver** accanto al riquadro **Schema**, trova il `Mutation` tipo, quindi il `publish(...): Channel` campo, quindi fai clic su Allega.**

Crea una fonte di dati *Nessuno* e assegnale un nome. *PageDataSource* Collegalo al tuo resolver.

Aggiungi l'implementazione del tuo resolver utilizzando il seguente frammento:

```
export function request(ctx) {
  return { payload: ctx.args };
}

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

Assicurati di creare il resolver e di salvare le modifiche apportate.

## Invia e sottoscrivi messaggi
<a name="send-and-subscribe-to-messages-js"></a>

Affinché i clienti possano ricevere messaggi, devono prima essere iscritti a una casella di posta.

Nel riquadro **Query**, esegui l'abbonamento: `SubscribeToData`

```
subscription SubscribeToData {
    subscribe(name:"channel") {
        name
        data
    }
}
```

 Il sottoscrittore riceverà messaggi ogni volta che viene richiamata la `publish` mutazione, ma solo quando il messaggio viene inviato all'abbonamento. `channel` **Proviamo a farlo nel riquadro Query.** Mentre l'abbonamento è ancora in esecuzione nella console, apri un'altra console ed esegui la seguente richiesta nel riquadro **Query**:

**Nota**  
In questo esempio utilizziamo stringhe JSON valide.

```
mutation PublishData {
    publish(data: "{\"msg\": \"hello world!\"}", name: "channel") {
        data
        name
    }
}
```

Il risultato sarà simile al seguente:

```
{
  "data": {
    "publish": {
      "data": "{\"msg\":\"hello world!\"}",
      "name": "channel"
    }
  }
}
```

Abbiamo appena dimostrato l'uso dei resolver locali, pubblicando un messaggio e ricevendolo senza uscire dal servizio. AWS AppSync 

# Combinazione di resolver GraphQL in AWS AppSync
<a name="tutorial-combining-graphql-resolvers-js"></a>

I resolver e i campi in uno schema di GraphQL hanno un rapporto 1:1 con un elevato grado di flessibilità. Poiché un'origine dati è configurata su un resolver indipendentemente da uno schema, hai la possibilità di risolvere o manipolare i tuoi tipi di GraphQL attraverso diverse fonti di dati, consentendoti di combinare uno schema per soddisfare al meglio le tue esigenze.

Gli scenari seguenti mostrano come combinare e abbinare le fonti di dati nello schema. Prima di iniziare, dovresti avere familiarità con la configurazione di sorgenti di dati e resolver per Amazon AWS Lambda DynamoDB e Amazon Service. OpenSearch 

## Schema di esempio
<a name="example-schema-js"></a>

Lo schema seguente ha un tipo di `Mutation` operazioni `Post` con tre `Query` e ciascuna:

```
type Post {
    id: ID!
    author: String!
    title: String
    content: String
    url: String
    ups: Int
    downs: Int
    version: Int!
}

type Query {
    allPost: [Post]
    getPost(id: ID!): Post
    searchPosts: [Post]
}

type Mutation {
    addPost(
        id: ID!,
        author: String!,
        title: String,
        content: String,
        url: String
    ): Post
    updatePost(
        id: ID!,
        author: String!,
        title: String,
        content: String,
        url: String,
        ups: Int!,
        downs: Int!,
        expectedVersion: Int!
    ): Post
    deletePost(id: ID!): Post
}
```

In questo esempio, avresti un totale di sei resolver, ognuno dei quali necessita di una fonte di dati. Un modo per risolvere questo problema sarebbe collegarli a una singola tabella Amazon DynamoDB, `Posts` chiamata, in cui `AllPost` il campo esegue una scansione e il campo esegue una query ([JavaScriptvedi riferimento `searchPosts` alla funzione resolver](https://docs.aws.amazon.com/appsync/latest/devguide/js-resolver-reference-dynamodb.html) per DynamoDB). Tuttavia, non sei limitato ad Amazon DynamoDB; esistono diverse fonti di dati come Lambda OpenSearch o Service per soddisfare le tue esigenze aziendali. 

## Alterazione dei dati tramite resolver
<a name="alter-data-through-resolvers-js"></a>

Potrebbe essere necessario restituire i risultati da un database di terze parti non supportato direttamente dalle fonti di dati. AWS AppSync Potrebbe inoltre essere necessario eseguire modifiche complesse sui dati prima che vengano restituiti ai client API. Ciò potrebbe essere causato da una formattazione impropria dei tipi di dati, ad esempio differenze di timestamp sui client o dalla gestione di problemi di compatibilità con le versioni precedenti. In questo caso, la soluzione appropriata è connettere AWS Lambda le funzioni come fonte di dati all' AWS AppSync API. A scopo illustrativo, nell'esempio seguente, una AWS Lambda funzione manipola i dati recuperati da un archivio dati di terze parti:

```
export const handler = (event, context, callback) => {
    // fetch data
    const result = fetcher()

    // apply complex business logic
    const data = transform(result)	

    // return to AppSync
    return data
};
```

Questa è una funzione di Lambda perfettamente valida e potrebbe essere associata al campo `AllPost` nello schema di GraphQL in modo che qualsiasi query che restituisce tutti i risultati ottenga numeri casuali per i voti in alto/in basso.

## DynamoDB e Service OpenSearch
<a name="ddb-and-es-js"></a>

Per alcune applicazioni, è possibile eseguire mutazioni o semplici query di ricerca su DynamoDB e disporre di un processo in background per trasferire i documenti al Service. OpenSearch È sufficiente collegare il `searchPosts` resolver all'origine dati del OpenSearch servizio e restituire i risultati della ricerca (dai dati originati in DynamoDB) utilizzando una query GraphQL. Ciò può rivelarsi estremamente efficace quando si aggiungono operazioni di ricerca avanzate alle applicazioni, ad esempio parole chiave, corrispondenze di parole confuse o persino ricerche geospaziali. Il trasferimento di dati da DynamoDB può essere eseguito tramite un processo ETL o, in alternativa, è possibile eseguire lo streaming da DynamoDB utilizzando Lambda.

Per iniziare con queste particolari fonti di dati, consulta i nostri tutorial su [DynamoDB](https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-dynamodb-resolvers-js.html) [e](https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-lambda-resolvers-js.html) Lambda.

Ad esempio, utilizzando lo schema del nostro tutorial precedente, la seguente mutazione aggiunge un elemento a DynamoDB:

```
mutation addPost {
  addPost(
    id: 123
    author: "Nadia"
    title: "Our first post!"
    content: "This is our first post."
    url: "https://aws.amazon.com/appsync/"
  ) {
    id
    author
    title
    content
    url
    ups
    downs
    version
  }
}
```

Questo scrive i dati su DynamoDB, che quindi trasmette i dati tramite Lambda ad OpenSearch Amazon Service, che poi usi per cercare post in base a campi diversi. Ad esempio, poiché i dati si trovano in Amazon OpenSearch Service, puoi cercare nei campi dell'autore o del contenuto con testo in formato libero, anche con spazi, come segue:

```
query searchName{
    searchAuthor(name:"   Nadia   "){
        id
        title
        content
    }
}

---------- or ----------

query searchContent{
    searchContent(text:"test"){
        id
        title
        content
    }
}
```

Poiché i dati vengono scritti direttamente su DynamoDB, è comunque possibile eseguire operazioni efficienti di ricerca di elenchi o elementi sulla tabella con le query and. `allPost{...}` `getPost{...}` Questo stack utilizza il seguente codice di esempio per i flussi DynamoDB:

**Nota**  
Questo codice Python è un esempio e non è pensato per essere utilizzato nel codice di produzione.

```
import boto3
import requests
from requests_aws4auth import AWS4Auth

region = '' # e.g. us-east-1
service = 'es'
credentials = boto3.Session().get_credentials()
awsauth = AWS4Auth(credentials.access_key, credentials.secret_key, region, service, session_token=credentials.token)

host = '' # the OpenSearch Service domain, e.g. https://search-mydomain.us-west-1.es.amazonaws.com
index = 'lambda-index'
datatype = '_doc'
url = host + '/' + index + '/' + datatype + '/'

headers = { "Content-Type": "application/json" }

def handler(event, context):
    count = 0
    for record in event['Records']:
        # Get the primary key for use as the OpenSearch ID
        id = record['dynamodb']['Keys']['id']['S']

        if record['eventName'] == 'REMOVE':
            r = requests.delete(url + id, auth=awsauth)
        else:
            document = record['dynamodb']['NewImage']
            r = requests.put(url + id, auth=awsauth, json=document, headers=headers)
        count += 1
    return str(count) + ' records processed.'
```

Puoi quindi utilizzare i flussi DynamoDB per collegarla a una tabella DynamoDB con una chiave primaria di e qualsiasi modifica all'origine `id` di DynamoDB verrà trasferita nel tuo dominio di servizio. OpenSearch Per ulteriori informazioni sulla configurazione di questa funzionalità, consulta [Documentazione dei flussi di DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.Lambda.html).

# Utilizzo dei OpenSearch resolver Amazon Service in AWS AppSync
<a name="tutorial-elasticsearch-resolvers-js"></a>

AWS AppSync supporta l'utilizzo di Amazon OpenSearch Service da domini che hai fornito nel tuo AWS account, a condizione che non esistano all'interno di un VPC. Dopo che sono stati assegnati i domini, è possibile connettersi a essi tramite un'origine dati, a quel punto è possibile configurare un resolver nello schema per eseguire operazioni di GraphQL, come ad esempio query, mutazioni e iscrizioni. Questo tutorial fornirà una descrizione di alcuni esempi comuni.

Per ulteriori informazioni, consulta la nostra guida di riferimento alla funzione [JavaScript resolver per](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-elasticsearch-js.html). OpenSearch

## Crea un nuovo dominio di servizio OpenSearch
<a name="create-a-new-es-domain-js"></a>

Per iniziare con questo tutorial, è necessario un dominio di OpenSearch servizio esistente. Se non si dispone di un dominio, è possibile usare il campione seguente. Tieni presente che possono essere necessari fino a 15 minuti per la creazione di un dominio di OpenSearch servizio prima di poter passare all'integrazione con una fonte di AWS AppSync dati.

```
aws cloudformation create-stack --stack-name AppSyncOpenSearch \
--template-url https://s3.us-west-2.amazonaws.com/awsappsync/resources/elasticsearch/ESResolverCFTemplate.yaml \
--parameters ParameterKey=OSDomainName,ParameterValue=ddtestdomain ParameterKey=Tier,ParameterValue=development \
--capabilities CAPABILITY_NAMED_IAM
```

Puoi avviare il seguente AWS CloudFormation stack nella regione US-West-2 (Oregon) nel tuo account: AWS 

 [https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks/new?templateURL=https://s3.us-west-2.amazonaws.com/awsappsync/resources/elasticsearch/ESResolverCFTemplate.yaml](https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks/new?templateURL=https://s3.us-west-2.amazonaws.com/awsappsync/resources/elasticsearch/ESResolverCFTemplate.yaml)

## Configura una fonte di dati per Service OpenSearch
<a name="configure-data-source-for-es-js"></a>

Dopo aver creato il dominio OpenSearch Service, accedi all'API AWS AppSync GraphQL e scegli la scheda **Data Sources**. Scegli **Crea origine dati** e inserisci un nome descrittivo per l'origine dati, ad esempio «*oss*». Quindi, scegli il ** OpenSearch dominio Amazon** per il **tipo di origine dati**, scegli la regione appropriata e dovresti vedere il tuo dominio di OpenSearch servizio elencato. Dopo averlo selezionato, puoi creare un nuovo ruolo e AWS AppSync assegnare le autorizzazioni appropriate al ruolo oppure puoi scegliere un ruolo esistente, con la seguente politica in linea:

Dovrai inoltre stabilire una relazione di fiducia con per quel ruolo: AWS AppSync 

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

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "appsync.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
```

------

Inoltre, il dominio OpenSearch Service ha una propria **politica di accesso** che puoi modificare tramite la console di Amazon OpenSearch Service. È necessario aggiungere una politica simile a quella riportata di seguito con le azioni e le risorse appropriate per il dominio del OpenSearch servizio. Tieni presente che il ruolo **Principal** sarà il ruolo dell'origine AWS AppSync dati, che può essere trovato nella console IAM se lasci che sia la console a crearlo.

## Collegamento di un resolver
<a name="connecting-a-resolver-js"></a>

Ora che l'origine dati è connessa al tuo dominio OpenSearch Service, puoi connetterla allo schema GraphQL con un resolver, come mostrato nell'esempio seguente:

```
 type Query {
   getPost(id: ID!): Post
   allPosts: [Post]
 }

 type Mutation {
   addPost(id: ID!, author: String, title: String, url: String, ups: Int, downs: Int, content: String): AWSJSON
 }

type Post {
  id: ID!
  author: String
  title: String
  url: String
  ups: Int
  downs: Int
  content: String
}
```

Si noti che vi è un tipo `Post` definito dall'utente con un campo di `id`. Negli esempi seguenti, supponiamo che esista un processo (che può essere automatizzato) per inserire questo tipo nel dominio di OpenSearch servizio, che verrebbe mappato alla radice del percorso in `/post/_doc` cui si `post` trova l'indice. Da questo percorso principale, è possibile eseguire ricerche su singoli documenti, ricerche con caratteri jolly o ricerche su più documenti con `/id/post*` un percorso di. `/post/_search` **Ad esempio, se avete un altro tipo chiamato`User`, potete indicizzare i documenti in base a un nuovo indice chiamato`user`, quindi eseguire ricerche con un percorso di.** `/user/_search` 

Dall'editor dello **schema** nella AWS AppSync console, modifica lo `Posts` schema precedente per includere una `searchPosts` query:

```
type Query {
  getPost(id: ID!): Post
  allPosts: [Post]
  searchPosts: [Post]
}
```

Salvare lo schema. **Nel **riquadro Resolver, trova `searchPosts` e** scegli Allega.** Scegli la fonte dei dati OpenSearch del servizio e salva il resolver. Aggiorna il codice del tuo resolver utilizzando lo snippet seguente:

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

/**
 * Searches for documents by using an input term
 * @param {import('@aws-appsync/utils').Context} ctx the context
 * @returns {*} the request
 */
export function request(ctx) {
	return {
		operation: 'GET',
		path: `/post/_search`,
		params: { body: { from: 0, size: 50 } },
	}
}

/**
 * Returns the fetched items
 * @param {import('@aws-appsync/utils').Context} ctx the context
 * @returns {*} the result
 */
export function response(ctx) {
	if (ctx.error) {
		util.error(ctx.error.message, ctx.error.type)
	}
	return ctx.result.hits.hits.map((hit) => hit._source)
}
```

Ciò presuppone che lo schema precedente contenga documenti che sono stati indicizzati in Service sotto il campo. OpenSearch `post` Se strutturi i dati in modo diverso, dovrai aggiornarli di conseguenza.

## Modificare le ricerche
<a name="modifying-your-searches-js"></a>

Il precedente gestore di richieste del resolver esegue una semplice interrogazione per tutti i record. Se si desidera eseguire la ricerca per un autore specifico Inoltre, supponiamo che tu voglia che quell'autore sia un argomento definito nella tua query GraphQL. Nell'editor dello **schema** della AWS AppSync console, aggiungi una `allPostsByAuthor` query:

```
type Query {
  getPost(id: ID!): Post
  allPosts: [Post]
  allPostsByAuthor(author: String!): [Post]
  searchPosts: [Post]
}
```

**Nel **riquadro Resolver**, trova `allPostsByAuthor` e scegli Allega.** Scegli l'origine dati del OpenSearch servizio e utilizza il seguente codice:

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

/**
 * Searches for documents by `author`
 * @param {import('@aws-appsync/utils').Context} ctx the context
 * @returns {*} the request
 */
export function request(ctx) {
	return {
		operation: 'GET',
		path: '/post/_search',
		params: {
			body: {
				from: 0,
				size: 50,
				query: { match: { author: ctx.args.author } },
			},
		},
	}
}

/**
 * Returns the fetched items
 * @param {import('@aws-appsync/utils').Context} ctx the context
 * @returns {*} the result
 */
export function response(ctx) {
	if (ctx.error) {
		util.error(ctx.error.message, ctx.error.type)
	}
	return ctx.result.hits.hits.map((hit) => hit._source)
}
```

Si noti che `body` viene popolato con una query del termine per il campo `author`, che è già passato attraverso il client come argomento. Facoltativamente, puoi utilizzare informazioni precompilate, come testo standard.

## Aggiungere dati al servizio OpenSearch
<a name="adding-data-to-es-js"></a>

Potresti voler aggiungere dati al tuo dominio di OpenSearch servizio come risultato di una mutazione GraphQL. Si tratta di un meccanismo potente per le ricerche e altri scopi. Poiché puoi utilizzare gli abbonamenti GraphQL per [rendere i tuoi dati in tempo reale](aws-appsync-real-time-data.md), può fungere da meccanismo per notificare ai clienti gli aggiornamenti dei dati nel tuo dominio di servizio. OpenSearch 

Torna alla pagina **Schema** nella AWS AppSync console e seleziona **Allega** per la mutazione. `addPost()` Seleziona nuovamente l'origine dati del OpenSearch servizio e utilizza il codice seguente:

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

/**
 * Searches for documents by `author`
 * @param {import('@aws-appsync/utils').Context} ctx the context
 * @returns {*} the request
 */
export function request(ctx) {
	return {
		operation: 'PUT',
		path: `/post/_doc/${ctx.args.id}`,
		params: { body: ctx.args },
	}
}

/**
 * Returns the inserted post
 * @param {import('@aws-appsync/utils').Context} ctx the context
 * @returns {*} the result
 */
export function response(ctx) {
	if (ctx.error) {
		util.error(ctx.error.message, ctx.error.type)
	}
	return ctx.result
}
```

Come in precedenza, questo è un esempio di come potrebbero essere strutturati i dati. Se hai nomi o indici di campo diversi, devi aggiornare `path` and`body`. Questo esempio mostra anche come utilizzare`context.arguments`, che può anche essere scritto come`ctx.args`, nel gestore delle richieste.

## Recupero di un singolo documento
<a name="retrieving-a-single-document-js"></a>

**Infine, se desideri utilizzare la `getPost(id:ID)` query nello schema per restituire un singolo documento, trova questa query nell'editor di **schemi** della AWS AppSync console e scegli Allega.** Seleziona nuovamente l'origine dati del OpenSearch servizio e utilizza il seguente codice:

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

/**
 * Searches for documents by `author`
 * @param {import('@aws-appsync/utils').Context} ctx the context
 * @returns {*} the request
 */
export function request(ctx) {
	return {
		operation: 'GET',
		path: `/post/_doc/${ctx.args.id}`,
	}
}

/**
 * Returns the post
 * @param {import('@aws-appsync/utils').Context} ctx the context
 * @returns {*} the result
 */
export function response(ctx) {
	if (ctx.error) {
		util.error(ctx.error.message, ctx.error.type)
	}
	return ctx.result._source
}
```

## Esegui interrogazioni e mutazioni
<a name="tutorial-elasticsearch-resolvers-perform-queries-mutations-js"></a>

Ora dovresti essere in grado di eseguire operazioni GraphQL sul tuo dominio di OpenSearch servizio. Vai alla scheda **Query** della AWS AppSync console e aggiungi un nuovo record:

```
mutation AddPost {
    addPost (
        id:"12345"
        author: "Fred"
        title: "My first book"
        content: "This will be fun to write!"
        url: "publisher website",
        ups: 100,
        downs:20 
       )
}
```

Vedrai il risultato della mutazione sulla destra. Allo stesso modo, ora puoi eseguire una `searchPosts` query sul tuo dominio OpenSearch di servizio:

```
query search {
    searchPosts {
        id
        title
        author
        content
    }
}
```

## Best practice
<a name="best-practices-js"></a>
+ OpenSearch Il servizio deve essere utilizzato per l'interrogazione dei dati, non come database principale. [Potresti voler utilizzare OpenSearch Service insieme ad Amazon DynamoDB, come indicato in Combined GraphQL Resolvers.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-combining-graphql-resolvers-js.html)
+ Concedi l'accesso al tuo dominio solo consentendo al ruolo di servizio di accedere al cluster. AWS AppSync 
+ È possibile iniziare con una soluzione di base in fase di sviluppo, con il cluster dal prezzo più basso, e quindi spostarsi in un cluster più grande con elevata disponibilità quando si passa alla produzione.

# Esecuzione di transazioni DynamoDB in AWS AppSync
<a name="tutorial-dynamodb-transact-js"></a>

AWS AppSync supporta l'utilizzo di operazioni di transazione Amazon DynamoDB su una o più tabelle in una singola regione. Le operazioni supportate sono `TransactGetItems` e `TransactWriteItems`. Utilizzando queste funzionalità in AWS AppSync, puoi eseguire attività come:
+ 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 una singola query
+ Scrittura dei record nelle transazioni su una o più tabelle in qualsiasi all-or-nothing modo
+ Esecuzione di transazioni quando vengono soddisfatte alcune condizioni

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

Come altri resolver, è necessario creare un'origine dati in AWS AppSync e creare un ruolo o utilizzarne uno esistente. Poiché le operazioni di transazione 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:DeleteItem",
                "dynamodb:GetItem",
                "dynamodb:PutItem",
                "dynamodb:Query",
                "dynamodb:Scan",
                "dynamodb:UpdateItem"
            ],
            "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 origini dati configurate per il recupero con DynamoDB hanno solo una tabella specificata per semplificare le configurazioni. Pertanto, quando si esegue un'operazione di transazione 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. La configurazione delle chiamate di transazione rispetto alle tabelle viene eseguita nel codice del resolver, che descriveremo di seguito.

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

Per semplicità, useremo la stessa origine dati per tutti i resolver usati in questo tutorial. 

**Avremo due tabelle chiamate **SavingAccounts** **e** CheckingAccounts, entrambe `accountNumber` con la chiave di partizione e una tabella TransactionHistory con come chiave di partizione.** `transactionId` È possibile utilizzare i comandi CLI riportati di seguito per creare le tabelle. Assicurati di sostituirlo `region` con la tua regione.

**Con la CLI**

```
aws dynamodb create-table --table-name savingAccounts \
  --attribute-definitions AttributeName=accountNumber,AttributeType=S \
  --key-schema AttributeName=accountNumber,KeyType=HASH \
  --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
  --table-class STANDARD --region region

aws dynamodb create-table --table-name checkingAccounts \
  --attribute-definitions AttributeName=accountNumber,AttributeType=S \
  --key-schema AttributeName=accountNumber,KeyType=HASH \
  --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
  --table-class STANDARD --region region

aws dynamodb create-table --table-name transactionHistory \
  --attribute-definitions AttributeName=transactionId,AttributeType=S \
  --key-schema AttributeName=transactionId,KeyType=HASH \
  --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 \
  --table-class STANDARD --region region
```

Nella AWS AppSync console, in **Sorgenti dati**, crea una nuova origine dati DynamoDB e assegnale un nome. **TransactTutorial** Seleziona **SavingAccounts** come tabella (sebbene la tabella specifica non abbia importanza quando si utilizzano le transazioni). Scegli di creare un nuovo ruolo e l'origine dati. Puoi rivedere la configurazione dell'origine dati per vedere il nome del ruolo generato. Nella console IAM, puoi aggiungere una policy in linea che consente all'origine dati di interagire con tutte le tabelle.

Sostituisci `region` e `accountID` con la tua regione e l'ID dell'account:

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

****  

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

------

## Transazioni
<a name="transactions-js"></a>

Per questo esempio, il contesto è una classica transazione bancaria, in cui useremo `TransactWriteItems` per:
+ Trasferire denaro dai conti di deposito ai conti correnti
+ Generare nuovi record di transazione per ogni transazione

Quindi, useremo `TransactGetItems` per recuperare i dettagli dai conti di deposito ai conti correnti.

**avvertimento**  
`TransactWriteItems`non è supportato se utilizzato per il rilevamento e la risoluzione dei conflitti. Queste impostazioni devono essere disabilitate per evitare possibili errori.

Definiamo il nostro schema GraphQL come segue:

```
type SavingAccount {
    accountNumber: String!
    username: String
    balance: Float
}

type CheckingAccount {
    accountNumber: String!
    username: String
    balance: Float
}

type TransactionHistory {
    transactionId: ID!
    from: String
    to: String
    amount: Float
}

type TransactionResult {
    savingAccounts: [SavingAccount]
    checkingAccounts: [CheckingAccount]
    transactionHistory: [TransactionHistory]
}

input SavingAccountInput {
    accountNumber: String!
    username: String
    balance: Float
}

input CheckingAccountInput {
    accountNumber: String!
    username: String
    balance: Float
}

input TransactionInput {
    savingAccountNumber: String!
    checkingAccountNumber: String!
    amount: Float!
}

type Query {
    getAccounts(savingAccountNumbers: [String], checkingAccountNumbers: [String]): TransactionResult
}

type Mutation {
    populateAccounts(savingAccounts: [SavingAccountInput], checkingAccounts: [CheckingAccountInput]): TransactionResult
    transferMoney(transactions: [TransactionInput]): TransactionResult
}
```

### TransactWriteItems - Compila gli account
<a name="transactwriteitems-populate-accounts-js"></a>

Al fine di trasferire denaro tra gli account, abbiamo bisogno di popolare la tabella con i dettagli. Per farlo, useremo l'operazione GraphQL `Mutation.populateAccounts`.

Nella sezione Schema, fai clic su **Allega** accanto all'`Mutation.populateAccounts`operazione. Scegli l'origine `TransactTutorial` dati e scegli **Crea**.

Ora usa il seguente codice:

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

export function request(ctx) {
	const { savingAccounts, checkingAccounts } = ctx.args

	const savings = savingAccounts.map(({ accountNumber, ...rest }) => {
		return {
			table: 'savingAccounts',
			operation: 'PutItem',
			key: util.dynamodb.toMapValues({ accountNumber }),
			attributeValues: util.dynamodb.toMapValues(rest),
		}
	})

	const checkings = checkingAccounts.map(({ accountNumber, ...rest }) => {
		return {
			table: 'checkingAccounts',
			operation: 'PutItem',
			key: util.dynamodb.toMapValues({ accountNumber }),
			attributeValues: util.dynamodb.toMapValues(rest),
		}
	})
	return {
		version: '2018-05-29',
		operation: 'TransactWriteItems',
		transactItems: [...savings, ...checkings],
	}
}

export function response(ctx) {
	if (ctx.error) {
		util.error(ctx.error.message, ctx.error.type, null, ctx.result.cancellationReasons)
	}
	const { savingAccounts: sInput, checkingAccounts: cInput } = ctx.args
	const keys = ctx.result.keys
	const savingAccounts = sInput.map((_, i) => keys[i])
	const sLength = sInput.length
	const checkingAccounts = cInput.map((_, i) => keys[sLength + i])
	return { savingAccounts, checkingAccounts }
}
```

Salva il resolver e vai alla sezione **Query** della AWS AppSync console per popolare gli account.

Eseguire la mutazione seguente:

```
mutation populateAccounts {
  populateAccounts (
    savingAccounts: [
      {accountNumber: "1", username: "Tom", balance: 100},
      {accountNumber: "2", username: "Amy", balance: 90},
      {accountNumber: "3", username: "Lily", balance: 80},
    ]
    checkingAccounts: [
      {accountNumber: "1", username: "Tom", balance: 70},
      {accountNumber: "2", username: "Amy", balance: 60},
      {accountNumber: "3", username: "Lily", balance: 50},
    ]) {
    savingAccounts {
      accountNumber
    }
    checkingAccounts {
      accountNumber
    }
  }
}
```

Abbiamo popolato tre conti di risparmio e tre conti correnti in un'unica mutazione.

****Utilizza la console DynamoDB per verificare che i dati vengano visualizzati nelle tabelle SavingAccounts e CheckingAccounts.****

### TransactWriteItems - Trasferisci denaro
<a name="transactwriteitems-transfer-money-js"></a>

Collega un resolver alla `transferMoney` mutazione con il seguente codice. Per ogni trasferimento, abbiamo bisogno di un modificatore di successo sia per il conto corrente che per il conto di risparmio e dobbiamo tenere traccia del trasferimento nelle transazioni.

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

export function request(ctx) {
	const transactions = ctx.args.transactions

	const savings = []
	const checkings = []
	const history = []
	transactions.forEach((t) => {
		const { savingAccountNumber, checkingAccountNumber, amount } = t
		savings.push({
			table: 'savingAccounts',
			operation: 'UpdateItem',
			key: util.dynamodb.toMapValues({ accountNumber: savingAccountNumber }),
			update: {
				expression: 'SET balance = balance - :amount',
				expressionValues: util.dynamodb.toMapValues({ ':amount': amount }),
			},
		})
		checkings.push({
			table: 'checkingAccounts',
			operation: 'UpdateItem',
			key: util.dynamodb.toMapValues({ accountNumber: checkingAccountNumber }),
			update: {
				expression: 'SET balance = balance + :amount',
				expressionValues: util.dynamodb.toMapValues({ ':amount': amount }),
			},
		})
		history.push({
			table: 'transactionHistory',
			operation: 'PutItem',
			key: util.dynamodb.toMapValues({ transactionId: util.autoId() }),
			attributeValues: util.dynamodb.toMapValues({
				from: savingAccountNumber,
				to: checkingAccountNumber,
				amount,
			}),
		})
	})

	return {
		version: '2018-05-29',
		operation: 'TransactWriteItems',
		transactItems: [...savings, ...checkings, ...history],
	}
}

export function response(ctx) {
	if (ctx.error) {
		util.error(ctx.error.message, ctx.error.type, null, ctx.result.cancellationReasons)
	}
	const tInput = ctx.args.transactions
	const tLength = tInput.length
	const keys = ctx.result.keys
	const savingAccounts = tInput.map((_, i) => keys[tLength * 0 + i])
	const checkingAccounts = tInput.map((_, i) => keys[tLength * 1 + i])
	const transactionHistory = tInput.map((_, i) => keys[tLength * 2 + i])
	return { savingAccounts, checkingAccounts, transactionHistory }
}
```

Ora, vai alla sezione **Queries** della AWS AppSync console ed esegui la mutazione **TransferMoney** come segue:

```
mutation write {
  transferMoney(
    transactions: [
      {savingAccountNumber: "1", checkingAccountNumber: "1", amount: 7.5},
      {savingAccountNumber: "2", checkingAccountNumber: "2", amount: 6.0},
      {savingAccountNumber: "3", checkingAccountNumber: "3", amount: 3.3}
    ]) {
    savingAccounts {
      accountNumber
    }
    checkingAccounts {
      accountNumber
    }
    transactionHistory {
      transactionId
    }
  }
}
```

Abbiamo inviato tre transazioni bancarie in un'unica mutazione. ****Utilizza la console DynamoDB per verificare che i dati vengano visualizzati nelle tabelle **SavingAccounts**, CheckingAccounts e TransactionHistory.****

### TransactGetItems - Recupera gli account
<a name="transactgetitems-retrieve-accounts-js"></a>

Per recuperare i dettagli dai conti di risparmio e correnti in un'unica richiesta transazionale, collegheremo un resolver all'operazione `Query.getAccounts` GraphQL sul nostro schema. Seleziona **Allega**, scegli la stessa fonte di `TransactTutorial` dati creata all'inizio del tutorial. Eseguire il seguente codice: 

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

export function request(ctx) {
	const { savingAccountNumbers, checkingAccountNumbers } = ctx.args

	const savings = savingAccountNumbers.map((accountNumber) => {
		return { table: 'savingAccounts', key: util.dynamodb.toMapValues({ accountNumber }) }
	})
	const checkings = checkingAccountNumbers.map((accountNumber) => {
		return { table: 'checkingAccounts', key: util.dynamodb.toMapValues({ accountNumber }) }
	})
	return {
		version: '2018-05-29',
		operation: 'TransactGetItems',
		transactItems: [...savings, ...checkings],
	}
}

export function response(ctx) {
	if (ctx.error) {
		util.error(ctx.error.message, ctx.error.type, null, ctx.result.cancellationReasons)
	}

	const { savingAccountNumbers: sInput, checkingAccountNumbers: cInput } = ctx.args
	const items = ctx.result.items
	const savingAccounts = sInput.map((_, i) => items[i])
	const sLength = sInput.length
	const checkingAccounts = cInput.map((_, i) => items[sLength + i])
	return { savingAccounts, checkingAccounts }
}
```

Salvare il resolver e passare alle sezioni **Query** della console AWS AppSync . Per recuperare i conti di risparmio e i conti correnti, esegui la seguente query:

```
query getAccounts {
  getAccounts(
    savingAccountNumbers: ["1", "2", "3"],
    checkingAccountNumbers: ["1", "2"]
  ) {
    savingAccounts {
      accountNumber
      username
      balance
    }
    checkingAccounts {
      accountNumber
      username
      balance
    }
  }
}
```

Abbiamo dimostrato con successo l'uso delle transazioni DynamoDB utilizzando. AWS AppSync

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

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`. Utilizzando queste funzionalità in AWS AppSync, puoi eseguire attività come:
+ 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 una singola query
+ Scrittura di record in blocco su una o più tabelle
+ Scrittura o eliminazione condizionale di record in più tabelle che potrebbero avere una relazione

Le operazioni 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 accederà il resolver.
+ La specifica della tabella per un resolver fa parte dell'oggetto della richiesta.

## Batch a tabella singola
<a name="single-table-batch-js"></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 iniziare, creiamo una nuova API GraphQL. Nella AWS AppSync console, scegli **Create API**, **GraphQL APIs** e **Design da zero**. **Assegna un nome all'API`BatchTutorial API`, scegli **Avanti** e nel passaggio **Specificare le risorse GraphQL, scegli Crea risorse** **GraphQL in un secondo momento e fai clic** su Avanti.** Controlla i tuoi dati e crea l'API. Vai alla pagina **Schema** e incolla lo schema seguente, notando che per la query inseriremo 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]
}
```

Salva lo schema e scegli **Crea risorse** nella parte superiore della pagina. Scegli **Usa il tipo esistente** e seleziona il `Post` tipo. Assegna un nome alla tua tabella`Posts`. **Assicurati che la **chiave primaria** sia impostata su`id`, deseleziona **Genera automaticamente GraphQL** (fornirai il tuo codice) e seleziona Crea.** Per iniziare, AWS AppSync crea una nuova tabella DynamoDB e un'origine dati connessa alla tabella con i ruoli appropriati. Tuttavia, ci sono ancora un paio di autorizzazioni da aggiungere al ruolo. Vai alla pagina **Fonti di dati** e scegli la nuova fonte di dati. In **Seleziona un ruolo esistente**, noterai che un ruolo è stato creato automaticamente per la tabella. Prendi nota del ruolo (dovrebbe assomigliare a qualcosa del genere`appsync-ds-ddb-aaabbbcccddd-Posts`) e poi vai alla console IAM ([https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/)). Nella console IAM, scegli **Ruoli**, quindi scegli il tuo ruolo dalla tabella. Nel tuo ruolo, in **Politiche di autorizzazione**, fai clic sul pulsante `+` "" accanto alla politica (dovrebbe avere un nome simile al nome del ruolo). Scegli **Modifica** nella parte superiore del pannello comprimibile quando viene visualizzata la politica. Devi aggiungere autorizzazioni batch alla tua politica, in particolare `dynamodb:BatchGetItem` e. `dynamodb:BatchWriteItem` Assomiglierà a questo:

------
#### [ 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/*"
            ]
        }
    ]
}
```

------

Scegli **Avanti**, quindi **Salva modifiche**. La tua politica dovrebbe ora consentire l'elaborazione in batch.

Tornando alla AWS AppSync console, vai alla pagina **Schema** e seleziona **Allega** accanto al `Mutation.batchAdd` campo. Crea il tuo resolver usando la `Posts` tabella come fonte di dati. Nell'editor di codice, sostituisci i gestori con lo snippet riportato di seguito. Questo frammento prende automaticamente ogni elemento del `input PostInput` tipo GraphQL e crea una mappa, necessaria per l'operazione: `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;
}
```

Vai alla pagina **Query** della AWS AppSync console ed esegui 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; questo può essere convalidato esaminando la console DynamoDB per cercare i valori scritti nella tabella. `Posts`

Quindi, ripeti il processo di collegamento di un resolver ma per il `Query.batchGet` campo utilizzando la `Posts` tabella come fonte di dati. Sostituisci i gestori con il codice seguente. Questo prende automaticamente ogni voce nel tipo `ids:[]` di GraphQL e crea una mappa, che risulta necessaria per l'operazione `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;
}
```

Ora torna alla pagina **Query della AWS AppSync console ed esegui la seguente query**: `batchGet`

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

Questo dovrebbe restituire i risultati per i due valori `id` aggiunti in precedenza. Nota che è stato restituito un `null` valore per il `id` con un valore di`3`. Questo perché non c'era ancora nessun record nella `Posts` tabella con quel valore. Tieni inoltre presente che AWS AppSync restituisce i risultati nello stesso ordine delle chiavi passate alla query, che è una funzionalità aggiuntiva che viene AWS AppSync eseguita per conto dell'utente. Quindi, se passi a`batchGet(ids:[1,3,2])`, vedrai che l'ordine è cambiato. È inoltre possibile sapere quale `id` ha restituito un valore `null`.

Infine, collega un altro resolver al `Mutation.batchDelete` campo usando la `Posts` tabella come fonte di dati. Sostituisci i gestori con il codice seguente. Questo prende automaticamente ogni voce nel tipo `ids:[]` di GraphQL e crea una mappa, che risulta necessaria per l'operazione `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;
}
```

Ora torna alla pagina **Queries** della AWS AppSync console ed esegui 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 multitavola
<a name="multi-table-batch-js"></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. Immagina di costruire un'app per la salute degli animali domestici in cui i sensori segnalano la posizione e la temperatura corporea dell'animale. 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 API. AWS AppSync 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.

Nella AWS AppSync console, scegli **Create API**, **GraphQL APIs** e **Design da zero**. **Assegna un nome all'API`MultiBatchTutorial API`, scegli **Avanti** e nel passaggio **Specificare le risorse GraphQL, scegli Crea risorse** **GraphQL in un secondo momento e fai clic** su Avanti.** Controlla i tuoi dati e crea l'API. Vai alla pagina **Schema** e incolla e salva lo schema seguente:

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

Dobbiamo creare due tabelle DynamoDB:
+ `locationReadings`memorizzerà le letture sulla posizione del sensore.
+ `temperatureReadings`memorizzerà le letture della temperatura del sensore.

Entrambe le tabelle condivideranno la stessa struttura di chiave primaria: `sensorId (String)` come chiave di partizione e `timestamp (String)` come chiave di ordinamento.

Scegli **Crea risorse** nella parte superiore della pagina. Scegli **Usa il tipo esistente** e seleziona il `locationReadings` tipo. Assegna un nome alla tua tabella`locationReadings`. Assicurati che la **chiave primaria** sia impostata su `sensorId` e la chiave di ordinamento su`timestamp`. **Deseleziona **Genera automaticamente GraphQL** (dovrai fornire il tuo codice) e seleziona Crea.** Ripeti questo processo per `temperatureReadings` utilizzare `temperatureReadings` come nome del tipo e della tabella. Utilizzate gli stessi tasti di cui sopra.

Le nuove tabelle conterranno ruoli generati automaticamente. Ci sono ancora un paio di autorizzazioni da aggiungere a questi ruoli. Vai alla pagina **Fonti di dati** e scegli`locationReadings`. In **Seleziona un ruolo esistente**, puoi vedere il ruolo. Prendi nota del ruolo (dovrebbe assomigliare a qualcosa del genere`appsync-ds-ddb-aaabbbcccddd-locationReadings`) e poi vai alla console IAM ([https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/)). Nella console IAM, scegli **Ruoli**, quindi scegli il tuo ruolo dalla tabella. Nel tuo ruolo, in **Politiche di autorizzazione**, fai clic sul pulsante `+` "" accanto alla politica (dovrebbe avere un nome simile al nome del ruolo). Scegli **Modifica** nella parte superiore del pannello comprimibile quando viene visualizzata la politica. È necessario aggiungere autorizzazioni a questa politica. Avrà un aspetto simile a questo:

Scegli **Avanti**, quindi **Salva modifiche**. Ripeti questo processo per l'origine `temperatureReadings` dati utilizzando lo stesso frammento di policy riportato sopra.

### BatchPutItem - Registrazione delle letture del sensore
<a name="batchputitem-recording-sensor-readings-js"></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. Dovremo aggiungere un resolver a questo campo.

Nella pagina **Schema** della AWS AppSync console, seleziona **Allega** accanto al `Mutation.recordReadings` campo. Nella schermata successiva, crea il tuo resolver usando la `locationReadings` tabella come fonte di dati.

Dopo aver creato il resolver, sostituisci i gestori con il seguente codice nell'editor. Questa `BatchPutItem` operazione ci consente di specificare più tabelle: 

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

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()` è simile a`util.error()`, con la principale distinzione che non interrompe la valutazione del gestore della richiesta o della risposta. Segnala invece che c'è stato un errore nel campo ma consente di valutare il gestore e di conseguenza di restituire i dati al chiamante. Si consiglia di utilizzarlo `utils.appendError()` quando l'applicazione deve restituire risultati parziali.

Salva il resolver e vai alla pagina **Query** nella console. AWS AppSync Ora possiamo inviare alcune letture dei sensori.

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

Abbiamo inviato dieci letture dei sensori in un'unica mutazione con letture suddivise su due tabelle. Utilizza la console DynamoDB per verificare che i dati vengano visualizzati sia nelle tabelle che nelle tabelle. `locationReadings` `temperatureReadings`

### BatchDeleteItem - Eliminazione delle letture dei sensori
<a name="batchdeleteitem-deleting-sensor-readings-js"></a>

Allo stesso modo, avremmo anche bisogno di poter eliminare lotti di letture dei sensori. Utilizzare il campo `Mutation.deleteReadings` di GraphQL per questo scopo. Nella pagina **Schema** della AWS AppSync console, seleziona **Allega** accanto al `Mutation.deleteReadings` campo. Nella schermata successiva, crea il tuo resolver usando la `locationReadings` tabella come fonte di dati.

Dopo aver creato il resolver, sostituisci i gestori nell'editor di codice con lo snippet riportato di seguito. In questo resolver, utilizziamo un mappatore di funzioni di supporto che estrae il e il dagli input forniti. `sensorId` `timestamp` 

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

**Salva il resolver e vai alla pagina Query nella console.** AWS AppSync Ora, eliminiamo 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
    }
  }
}
```

**Nota**  
A differenza dell'operazione `DeleteItem`, nella risposta non viene restituita la voce completamente eliminata. Viene restituita solo la chiave passata. Per ulteriori informazioni, consulta il [riferimento alla funzione BatchDeleteItem in JavaScript resolver per DynamoDB](https://docs.aws.amazon.com/appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-batch-delete-item).

Verifica tramite la console DynamoDB che queste due letture siano state eliminate dalle tabelle and. `locationReadings` `temperatureReadings`

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

Un'altra operazione comune per la nostra app sarebbe quella di recuperare le letture di un sensore in un momento specifico. Allegare un resolver al campo `Query.getReadings` di GraphQL sullo schema. Nella pagina **Schema** della AWS AppSync console, seleziona **Allega** accanto al `Query.getReadings` campo. Nella schermata successiva, crea il tuo resolver usando la `locationReadings` tabella come fonte di dati.

Usiamo il codice seguente: 

```
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' })),
	]
}
```

Salva il resolver e vai alla pagina **Query** nella console. AWS AppSync Ora, recuperiamo le letture dei nostri sensori.

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 degli errori
<a name="error-handling-js"></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 l'opportunità di gestire gli errori nel gestore delle risposte. 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`. Nel gestore delle risposte, è possibile gestire i risultati parziali in tre modi:

1. Ingoia l'errore di invocazione semplicemente restituendo i dati.

1. Genera un errore (using`util.error(...)`) interrompendo la valutazione del gestore, che non restituirà alcun dato.

1. Aggiungi un errore (usando`util.appendError(...)`) e restituisci anche i dati.

Dimostriamo ciascuno dei tre punti precedenti con le operazioni batch di DynamoDB.

### Operazioni di batch di DynamoDB
<a name="dynamodb-batch-operations-js"></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 gli 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 durante il secondo tentativo AWS AppSync per elaborare gli elementi rimanenti del batch.

Il seguente codice JSON rappresenta il contesto serializzato dopo la chiamata in batch di DynamoDB ma prima della chiamata del gestore delle risposte:

```
{
  "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 vengono mappati per tabella sotto `ctx.result.data` anche se è presente un errore.
+ Le chiavi che non sono state elaborate sono disponibili all'indirizzo. `ctx.result.data.unprocessedKeys` In questo caso, 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-js"></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 codice che scriviamo è familiare e si concentra solo sui dati dei risultati.

**Gestore di risposte**

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

**Risposta 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 gestore di risposte
<a name="raising-an-error-to-abort-the-response-execution-js"></a>

Quando gli errori parziali devono essere trattati come errori completi dal punto di vista del client, è possibile interrompere l'esecuzione del gestore di risposte per impedire la restituzione dei dati. Il metodo di utilità `util.error(...)` raggiunge esattamente questo comportamento.

**Codice del gestore di risposte**

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

**Risposta 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-js"></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. `util.appendError(...)`È il metodo di utilità che abilita questo comportamento consentendo al progettista dell'applicazione di aggiungere errori al contesto senza interferire con la valutazione del gestore della risposta. Dopo aver valutato il gestore della risposta, AWS AppSync elaborerà eventuali errori di contesto aggiungendoli al blocco errors della risposta GraphQL.

**Codice del gestore di risposte**

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

Abbiamo inoltrato sia l'errore di invocazione che l'`unprocessedKeys`elemento all'interno del blocco errors della risposta GraphQL. Il `getReadings` campo restituisce anche dati parziali dalla `locationReadings` tabella, come puoi vedere nella risposta seguente.

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

# Utilizzo di resolver HTTP in AWS AppSync
<a name="tutorial-http-resolvers-js"></a>

AWS AppSync consente di utilizzare fonti di dati supportate (ad esempio Amazon DynamoDB AWS Lambda, Amazon Service o OpenSearch Amazon Aurora) per eseguire varie operazioni, oltre a qualsiasi endpoint HTTP arbitrario per risolvere i campi GraphQL. Quando gli endpoint HTTP sono disponibili, è possibile connettersi a questi utilizzando un'origine dati. Quindi, è possibile configurare un resolver nello schema per eseguire operazioni GraphQL, ad esempio query, mutazioni e sottoscrizioni. Questo tutorial fornirà una guida di alcuni esempi comuni.

In questo tutorial utilizzi un'API REST (creata utilizzando Amazon API Gateway e Lambda) con un endpoint GraphQL AWS AppSync .

## Creazione di un'API REST
<a name="creating-a-rest-api"></a>

Puoi utilizzare il seguente AWS CloudFormation modello per configurare un endpoint REST adatto a questo tutorial:

[https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks/new?templateURL=https://s3.us-west-2.amazonaws.com/awsappsync/resources/http/http-api-gw.yaml](https://console.aws.amazon.com/cloudformation/home?region=us-west-2#/stacks/new?templateURL=https://s3.us-west-2.amazonaws.com/awsappsync/resources/http/http-api-gw.yaml)

Lo AWS CloudFormation stack esegue i seguenti passaggi:

1. Imposta una funzione Lambda che contiene la logica di business per il tuo microservizio.

1. Imposta un'API REST API Gateway con la seguente combinazione endpoint/method/content di tipi:


****  

| Percorso risorsa API | Metodo HTTP | Tipo di contenuto supportato | 
| --- | --- | --- | 
|  /v1/utenti  |  POST  |  application/json  | 
|  /v1/utenti  |  GET  |  application/json  | 
|  /v1/utenti/1  |  GET  |  application/json  | 
|  /v1/utenti/1  |  PUT  |  application/json  | 
|  /v1/utenti/1  |  DELETE  |  application/json  | 

## Creazione dell'API GraphQL
<a name="creating-your-graphql-api"></a>

Per creare l'API GraphQL in: AWS AppSync

1. Apri la AWS AppSync console e scegli **Crea API**.

1. Scegli **GraphQL APIs** e poi scegli **Design da zero**. Scegli **Next (Successivo)**.

1. Per il nome API, digita `UserData`. Scegli **Next (Successivo)**.

1. Scegli `Create GraphQL resources later`. Scegli **Next (Successivo)**.

1. Controlla i tuoi input e scegli **Crea** API.

La AWS AppSync console crea una nuova API GraphQL utilizzando la modalità di autenticazione della chiave API. Puoi utilizzare la console per configurare ulteriormente l'API GraphQL ed eseguire le richieste.

## Creazione di uno schema GraphQL
<a name="creating-a-graphql-schema"></a>

Ora che hai un'API GraphQL, è possibile creare uno schema GraphQL. Nell'editor di **schema** della AWS AppSync console, usa lo snippet seguente:

```
type Mutation {
    addUser(userInput: UserInput!): User
    deleteUser(id: ID!): User
}

type Query {
    getUser(id: ID): User
    listUser: [User!]!
}

type User {
    id: ID!
    username: String!
    firstname: String
    lastname: String
    phone: String
    email: String
}

input UserInput {
    id: ID!
    username: String!
    firstname: String
    lastname: String
    phone: String
    email: String
}
```

## Configura la tua fonte di dati HTTP
<a name="configure-your-http-data-source"></a>

Per configurare l'origine dati HTTP, effettua le seguenti operazioni:

1. Nella pagina **Sorgenti dati** dell'API AWS AppSync GraphQL, scegli **Crea origine dati**.

1. Inserisci un nome per la fonte di dati, ad esempio`HTTP_Example`.

1. In **Tipo di origine dati**, scegli **Endpoint HTTP**.

1. Imposta l'endpoint sull'endpoint API Gateway creato all'inizio del tutorial. **Puoi trovare l'endpoint generato dallo stack accedendo alla console Lambda e trovando l'applicazione in Applicazioni.** All'interno delle impostazioni dell'applicazione, dovresti vedere un endpoint **API che fungerà da endpoint**. AWS AppSync Assicurati di non includere il nome dello stage come parte dell'endpoint. Ad esempio, se il tuo endpoint lo fosse`https://aaabbbcccd.execute-api.us-east-1.amazonaws.com/v1`, dovresti digitare. `https://aaabbbcccd.execute-api.us-east-1.amazonaws.com`

**Nota**  
Al momento, solo gli endpoint pubblici sono supportati da. AWS AppSync  
Per ulteriori informazioni sulle autorità di certificazione riconosciute dal AWS AppSync servizio, consulta [Autorità di certificazione (CA) riconosciute da AWS AppSync per gli endpoint HTTPS](http-cert-authorities.md#aws-appsync-http-certificate-authorities).

## Configurazione dei resolver
<a name="configuring-resolvers"></a>

In questo passaggio, collegherai l'origine dati HTTP alle query `getUser` and`addUser`.

Per configurare il `getUser` resolver:

1. Nella tua API AWS AppSync GraphQL, scegli la scheda **Schema**.

1. **A destra dell'editor dello **schema**, nel riquadro **Resolvers** e sotto il tipo di **query**, trova il `getUser` campo e scegli Allega.**

1. Mantieni invariato il tipo di resolver e il runtime inalterato`Unit`. `APPSYNC_JS`

1. Nel **Nome dell'origine dati**, scegli l'endpoint HTTP creato in precedenza.

1. Scegli **Create** (Crea).

1. Nell'editor di codice **Resolver**, aggiungi il seguente frammento come gestore delle richieste:

   ```
   import { util } from '@aws-appsync/utils'
   
   export function request(ctx) {
   	return {
   		version: '2018-05-29',
   		method: 'GET',
   		params: {
   			headers: {
   				'Content-Type': 'application/json',
   			},
   		},
   		resourcePath: `/v1/users/${ctx.args.id}`,
   	}
   }
   ```

1. Aggiungi il seguente frammento come gestore delle risposte:

   ```
   export function response(ctx) {
   	const { statusCode, body } = ctx.result
   	// if response is 200, return the response
   	if (statusCode === 200) {
   		return JSON.parse(body)
   	}
   	// if response is not 200, append the response to error block.
   	util.appendError(body, statusCode)
   }
   ```

1. Scegliere la scheda **Query** quindi eseguire la seguente query:

   ```
   query GetUser{
       getUser(id:1){
           id
           username
       }
   }
   ```

   Viene restituita la risposta seguente:

   ```
   {
       "data": {
           "getUser": {
               "id": "1",
               "username": "nadia"
           }
       }
   }
   ```

Per configurare il resolver: `addUser`

1. Scegli la scheda **Schema**.

1. **A destra dell'editor dello **schema**, nel riquadro **Resolver** e sotto il tipo di **query, trova il `addUser` campo** e scegli Allega.**

1. Mantieni invariato il tipo di resolver e il runtime inalterato`Unit`. `APPSYNC_JS`

1. Nel **Nome dell'origine dati**, scegli l'endpoint HTTP creato in precedenza.

1. Scegli **Create** (Crea).

1. Nell'editor di codice **Resolver**, aggiungi il seguente frammento come gestore delle richieste:

   ```
   export function request(ctx) {
       return {
           "version": "2018-05-29",
           "method": "POST",
           "resourcePath": "/v1/users",
           "params":{
               "headers":{
                   "Content-Type": "application/json"
               },
           "body": ctx.args.userInput
           }
       }
   }
   ```

1. Aggiungi il seguente frammento come gestore delle risposte:

   ```
   export function response(ctx) {
       if(ctx.error) {
           return util.error(ctx.error.message, ctx.error.type)
       }
       if (ctx.result.statusCode == 200) {
           return ctx.result.body
       } else {
           return util.appendError(ctx.result.body, "ctx.result.statusCode")
       }
   }
   ```

1. Scegliere la scheda **Query** quindi eseguire la seguente query:

   ```
   mutation addUser{
       addUser(userInput:{
           id:"2",
           username:"shaggy"
       }){
           id
           username
       }
   }
   ```

   Se esegui nuovamente la `getUser` query, dovrebbe restituire la seguente risposta:

   ```
   {
       "data": {
           "getUser": {
           "id": "2",
           "username": "shaggy"
           }
       }
   }
   ```

## Richiamo dei servizi AWS
<a name="invoking-aws-services-js"></a>

È possibile utilizzare i resolver HTTP per configurare un'interfaccia API GraphQL per i servizi. AWS Le richieste HTTP AWS devono essere firmate con il [processo Signature Version 4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html) in modo da AWS poter identificare chi le ha inviate. AWS AppSync calcola la firma per tuo conto quando associ un ruolo IAM all'origine dati HTTP.

Fornisci due componenti aggiuntivi per richiamare i AWS servizi con resolver HTTP:
+ Un ruolo IAM con autorizzazioni per chiamare il servizio AWS APIs
+ Configurazione della firma nell'origine dati

Ad esempio, se desideri chiamare l'[ListGraphqlApis operazione](https://docs.aws.amazon.com/appsync/latest/APIReference/API_ListGraphqlApis.html) con resolver HTTP, devi prima [creare un ruolo IAM](attaching-a-data-source.md#aws-appsync-getting-started-build-a-schema-from-scratch) che AWS AppSync presuppone la seguente policy allegata:

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

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Action": [
                "appsync:ListGraphqlApis"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ]
}
```

------

Quindi, crea l'origine dati HTTP per. AWS AppSync In questo esempio, chiami AWS AppSync nella regione Stati Uniti occidentali (Oregon). Imposta la seguente configurazione HTTP in un file denominato `http.json`, che include la regione di firma e il nome del servizio:

```
{
    "endpoint": "https://appsync.us-west-2.amazonaws.com/",
    "authorizationConfig": {
        "authorizationType": "AWS_IAM",
        "awsIamConfig": {
            "signingRegion": "us-west-2",
            "signingServiceName": "appsync"
        }
    }
}
```

Quindi, utilizzate il AWS CLI per creare l'origine dati con un ruolo associato come segue:

```
aws appsync create-data-source --api-id <API-ID> \
                               --name AWSAppSync \
                               --type HTTP \
                               --http-config file:///http.json \
                               --service-role-arn <ROLE-ARN>
```

Quando colleghi un resolver al campo dello schema, usa il seguente modello di mappatura delle richieste per chiamare: AWS AppSync

```
{
    "version": "2018-05-29",
    "method": "GET",
    "resourcePath": "/v1/apis"
}
```

Quando esegui una query GraphQL per questa fonte di dati, AWS AppSync firma la richiesta utilizzando il ruolo che hai fornito e include la firma nella richiesta. La query restituisce un elenco di AWS AppSync GraphQL APIs nel tuo account in quella AWS regione.

# Utilizzo di Aurora PostgreSQL con Data API in AWS AppSync
<a name="aurora-serverless-tutorial-js"></a>

 

Scopri come connettere l'API GraphQL ai database Aurora PostgreSQL utilizzando. AWS AppSync Questa integrazione consente di creare applicazioni scalabili e basate sui dati eseguendo query e mutazioni SQL tramite operazioni GraphQL. AWS AppSync fornisce un'origine dati per l'esecuzione di istruzioni SQL su cluster Amazon Aurora abilitati con un'API Data. Puoi utilizzare AWS AppSync i resolver per eseguire istruzioni SQL sull'API dei dati con query, mutazioni e sottoscrizioni GraphQL.

Prima di iniziare questo tutorial, è necessario avere una conoscenza di base AWS dei servizi e dei concetti di GraphQL.

**Nota**  
In questo tutorial viene utilizzata la regione `US-EAST-1`. 

**Topics**
+ [Configura il tuo database Aurora PostgreSQL](#creating-clusters)
+ [Creazione del database e della tabella](#creating-db-table)
+ [Creazione di uno schema GraphQL](#rds-graphql-schema)
+ [Resolver per RDS](#rds-resolvers)
+ [Eliminazione del cluster](#rds-delete-cluster)

## Configura il tuo database Aurora PostgreSQL
<a name="creating-clusters"></a>

Prima di aggiungere un'origine dati Amazon RDS AWS AppSync, procedi come segue.

1. Abilita un'API dati su un cluster Aurora Serverless v2.

1. Configura un segreto utilizzando Gestione dei segreti AWS

1. Crea il cluster utilizzando il seguente AWS CLI comando.

   ```
   aws rds create-db-cluster \
               --db-cluster-identifier appsync-tutorial \
               --engine aurora-postgresql \
               --engine-version 16.6 \
               --serverless-v2-scaling-configuration MinCapacity=0,MaxCapacity=1 \
               --master-username USERNAME \
               --master-user-password COMPLEX_PASSWORD \
               --enable-http-endpoint
   ```

Verrà restituito un ARN per il cluster. Dopo aver creato un cluster, è necessario aggiungere un'istanza Serverless v2 con il comando seguente AWS CLI .

```
aws rds create-db-instance \
    --db-cluster-identifier appsync-tutorial \
    --db-instance-identifier appsync-tutorial-instance-1 \
    --db-instance-class db.serverless \
    --engine aurora-postgresql
```

**Nota**  
L'attivazione di questi endpoint richiede tempo. Puoi controllarne lo stato nella console RDS nella scheda **Connettività e sicurezza** del cluster.

Controlla lo stato del cluster con il seguente AWS CLI comando.

```
aws rds describe-db-clusters \
    --db-cluster-identifier appsync-tutorial \
    --query "DBClusters[0].Status"
```

Crea un segreto tramite la Gestione dei segreti AWS console o AWS CLI con un file di input come il seguente utilizzando i `USERNAME` e `COMPLEX_PASSWORD` del passaggio precedente:

```
{
    "username": "USERNAME",
    "password": "COMPLEX_PASSWORD"
}
```

Passalo come parametro a AWS CLI:

```
aws secretsmanager create-secret \
    --name appsync-tutorial-rds-secret \
    --secret-string file://creds.json
```

Verrà restituito un ARN per il segreto. **Prendi nota** dell'ARN del tuo cluster Aurora Serverless v2 e di Secret per dopo quando crei un'origine dati nella console. AWS AppSync 

## Creazione del database e della tabella
<a name="creating-db-table"></a>

Innanzitutto, crea un database denominato`TESTDB`. In PostgreSQL, un database è un contenitore che contiene tabelle e altri oggetti SQL. Verifica che il cluster Aurora Serverless v2 sia configurato correttamente prima di aggiungerlo all'API. AWS AppSync Innanzitutto, crea un database *TESTDB* con il parametro seguente. `--sql`

```
aws rds-data execute-statement \
    --resource-arn "arn:aws:rds:us-east-1:111122223333 ISN:cluster:appsync-tutorial" \
    --secret-arn "arn:aws:secretsmanager:us-east-1:111122223333 ISN:secret:appsync-tutorial-rds-secret" \
    --sql "create DATABASE \"testdb\"" \
    --database "postgres"
```

 Se viene eseguito senza errori, aggiungete due tabelle con il `create table` comando:

```
 aws rds-data execute-statement \
    --resource-arn "arn:aws:rds:us-east-1:111122223333 ISN:cluster:appsync-tutorial" \
    --secret-arn "arn:aws:secretsmanager:us-east-1:111122223333 ISN:secret:appsync-tutorial-rds-secret" \
    --database "testdb" \
    --sql 'create table public.todos (id serial constraint todos_pk primary key, description text not null, due date not null, "createdAt" timestamp default now());'

aws rds-data execute-statement \
    --resource-arn "arn:aws:rds:us-east-1:111122223333 ISN:cluster:appsync-tutorial" \
    --secret-arn "arn:aws:secretsmanager:us-east-1:111122223333 ISN:secret:appsync-tutorial-rds-secret" \
    --database "testdb" \
    --sql 'create table public.tasks (id serial constraint tasks_pk primary key, description varchar, "todoId" integer not null constraint tasks_todos_id_fk references public.todos);'
```

In caso di successo, aggiungi il cluster come fonte di dati nella tua API.

## Creazione di uno schema GraphQL
<a name="rds-graphql-schema"></a>

Ora che la tua API dati Aurora Serverless v2 è in esecuzione con tabelle configurate, creeremo uno schema GraphQL. Puoi creare rapidamente la tua API importando le configurazioni delle tabelle da un database esistente utilizzando la procedura guidata di creazione dell'API.

Per iniziare: 

1. Nella AWS AppSync console, scegli **Crea API**, quindi **Inizia con un cluster Amazon Aurora**. 

1. Specificate i dettagli dell'**API, come il nome** dell'API, quindi selezionate il database per generare l'API.

1. Scegli il tuo database. Se necessario, aggiorna la regione, quindi scegli il cluster Aurora e il database *TESTDB*. 

1. **Scegli il tuo segreto, quindi scegli Importa.** 

1. Una volta scoperte le tabelle, aggiorna i nomi dei tipi. Passa `Todos` a `Todo` e `Tasks` a`Task`. 

1. Visualizza l'anteprima dello schema generato scegliendo **Anteprima schema**. Il tuo schema sarà simile al seguente: 

   ```
   type Todo {
     id: Int!
     description: String!
     due: AWSDate!
     createdAt: String
   }
   
   type Task {
     id: Int!
     todoId: Int!
     description: String
   }
   ```

1. Per il ruolo, puoi AWS AppSync creare un nuovo ruolo o crearne uno con una politica simile a quella seguente:

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

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "rds-data:ExecuteStatement"
               ],
               "Resource": [
                   "arn:aws:rds:us-east-1:111122223333:cluster:appsync-tutorial",
                   "arn:aws:rds:us-east-1:111122223333:cluster:appsync-tutorial:*"
               ]
           },
           {
               "Effect": "Allow",
               "Action": [
                   "secretsmanager:GetSecretValue"
               ],
               "Resource": [
               "arn:aws:secretsmanager:us-east-1:111122223333:secret:appsync-tutorial-rds-secret",
               "arn:aws:secretsmanager:us-east-1:111122223333:secret:appsync-tutorial-rds-secret:*"
               ]
           }
       ]
   }
   ```

------

   Tieni presente che ci sono due dichiarazioni in questa politica a cui concedi l'accesso al ruolo. La prima risorsa è il cluster Aurora e la seconda è l' Gestione dei segreti AWS ARN. 

   Scegli **Avanti**, esamina i dettagli di configurazione, quindi scegli **Crea** API. Ora hai un'API completamente operativa. Puoi rivedere tutti i dettagli della tua API nella pagina **Schema**. 

## Resolver per RDS
<a name="rds-resolvers"></a>

Il flusso di creazione dell'API ha creato automaticamente i resolver per interagire con i nostri tipi. Se guardi la pagina **Schema**, troverai dei resolver, alcuni dei seguenti resolver.
+ Crea `Mutation.createTodo` un tramite il campo. `todo`
+ Aggiorna un `todo` messaggio tramite il `Mutation.updateTodo` campo.
+ Elimina un `todo` tramite il `Mutation.deleteTodo` campo.
+ Acquistane uno `todo` tramite il `Query.getTodo` campo.
+ Elenca tutto `todos` tramite il `Query.listTodos` campo.

Troverai campi e resolver simili allegati per il tipo. `Task` Diamo un'occhiata più da vicino ad alcuni resolver. 

### Mutazione. CreateToDo
<a name="createtodo"></a>

Dall'editor dello schema nella AWS AppSync console, sul lato destro, scegli accanto a. `testdb` `createTodo(...): Todo` Il codice del resolver utilizza la `insert` funzione del `rds` modulo per creare dinamicamente un'istruzione insert che aggiunge dati alla tabella. `todos` Poiché stiamo lavorando con Postgres, possiamo sfruttare l'`returning`istruzione per recuperare i dati inseriti.

Aggiorna il seguente resolver per specificare correttamente il tipo di campo. `DATE` `due`

```
import { util } from '@aws-appsync/utils';
import { insert, createPgStatement, toJsonObject, typeHint } from '@aws-appsync/utils/rds';

export function request(ctx) {
    const { input } = ctx.args;
    // if a due date is provided, cast is as `DATE`
    if (input.due) {
        input.due = typeHint.DATE(input.due)
    }
    const insertStatement = insert({
        table: 'todos',
        values: input,
        returning: '*',
    });
    return createPgStatement(insertStatement)
}

export function response(ctx) {
    const { error, result } = ctx;
    if (error) {
        return util.appendError(
            error.message,
            error.type,
            result
        )
    }
    return toJsonObject(result)[0][0]
}
```

Salva il resolver. Il suggerimento sul tipo contrassegna `due` correttamente il nostro oggetto di input come tipo. `DATE` Ciò consente al motore Postgres di interpretare correttamente il valore. Quindi, aggiorna lo schema per rimuovere il `id` `CreateTodo` dall'input. Poiché il nostro database Postgres può restituire l'ID generato, puoi fare affidamento su di esso per la creazione e la restituzione del risultato come una singola richiesta come segue.

```
input CreateTodoInput {
    due: AWSDate!
    createdAt: String
    description: String!
}
```

Apporta la modifica e aggiorna lo schema. Vai all'editor **Queries** per aggiungere un elemento al database come segue.

```
mutation CreateTodo {
  createTodo(input: {description: "Hello World!", due: "2023-12-31"}) {
    id
    due
    description
    createdAt
  }
}
```

Ottieni il seguente risultato.

```
{
  "data": {
    "createTodo": {
      "id": 1,
      "due": "2023-12-31",
      "description": "Hello World!",
      "createdAt": "2023-11-14 20:47:11.875428"
    }
  }
}
```

### query.listToDos
<a name="listtodo"></a>

Dall'editor dello schema nella console, sul lato destro, scegli accanto a. `testdb` `listTodos(id: ID!): Todo` Il gestore delle richieste utilizza la funzione di utilità select per creare una richiesta in modo dinamico in fase di esecuzione.

```
export function request(ctx) {
    const { filter = {}, limit = 100, nextToken } = ctx.args;
    const offset = nextToken ? +util.base64Decode(nextToken) : 0;
    const statement = select({
        table: 'todos',
        columns: '*',
        limit,
        offset,
        where: filter,
    });
    return createPgStatement(statement)
}
```

Vogliamo filtrare in `todos` base alla `due` data. Aggiorniamo il resolver per trasmettere `due` i valori a. `DATE` Aggiorna l'elenco delle importazioni e il gestore delle richieste come segue.

```
import { util } from '@aws-appsync/utils';
import * as rds from '@aws-appsync/utils/rds';

export function request(ctx) {
  const { filter: where = {}, limit = 100, nextToken } = ctx.args;
  const offset = nextToken ? +util.base64Decode(nextToken) : 0;

  // if `due` is used in a filter, CAST the values to DATE.
  if (where.due) {
    Object.entries(where.due).forEach(([k, v]) => {
      if (k === 'between') {
        where.due[k] = v.map((d) => rds.typeHint.DATE(d));
      } else {
        where.due[k] = rds.typeHint.DATE(v);
      }
    });
  }

  const statement = rds.select({
    table: 'todos',
    columns: '*',
    limit,
    offset,
    where,
  });
  return rds.createPgStatement(statement);
}

export function response(ctx) {
  const {
    args: { limit = 100, nextToken },
    error,
    result,
  } = ctx;
  if (error) {
    return util.appendError(error.message, error.type, result);
  }
  const offset = nextToken ? +util.base64Decode(nextToken) : 0;
  const items = rds.toJsonObject(result)[0];
  const endOfResults = items?.length < limit;
  const token = endOfResults ? null : util.base64Encode(`${offset + limit}`);
  return { items, nextToken: token };
}
```

Nell'editor **Queries**, procedi come segue.

```
query LIST {
  listTodos(limit: 10, filter: {due: {between: ["2021-01-01", "2025-01-02"]}}) {
    items {
      id
      due
      description
    }
  }
}
```

### Mutation.UpdateToDo
<a name="updatetodo"></a>

Puoi anche un. `update` `Todo` Dall'editor di **Queries**, aggiorniamo il nostro primo `Todo` elemento di `id``1`.

```
mutation UPDATE {
  updateTodo(input: {id: 1, description: "edits"}) {
    description
    due
    id
  }
}
```

Nota che devi specificare `id` l'elemento che stai aggiornando. Puoi anche specificare una condizione per aggiornare solo un elemento che soddisfa condizioni specifiche. Ad esempio, potremmo voler modificare l'elemento solo se la descrizione inizia con la `edits` seguente.

```
mutation UPDATE {
  updateTodo(input: {id: 1, description: "edits: make a change"}, condition: {description: {beginsWith: "edits"}}) {
    description
    due
    id
  }
}
```

Proprio come abbiamo gestito le nostre `list` operazioni `create` e, allo stesso modo, possiamo aggiornare il nostro resolver per indirizzare il `due` campo a. `DATE` Salva queste modifiche come segue. `updateTodo`

```
import { util } from '@aws-appsync/utils';
import * as rds from '@aws-appsync/utils/rds';

export function request(ctx) {
  const { input: { id, ...values }, condition = {}, } = ctx.args;
  const where = { ...condition, id: { eq: id } };

  // if `due` is used in a condition, CAST the values to DATE.
  if (condition.due) {
    Object.entries(condition.due).forEach(([k, v]) => {
      if (k === 'between') {
        condition.due[k] = v.map((d) => rds.typeHint.DATE(d));
      } else {
        condition.due[k] = rds.typeHint.DATE(v);
      }
    });
  }

  // if a due date is provided, cast is as `DATE`
  if (values.due) {
    values.due = rds.typeHint.DATE(values.due);
  }

  const updateStatement = rds.update({
    table: 'todos',
    values,
    where,
    returning: '*',
  });
  return rds.createPgStatement(updateStatement);
}

export function response(ctx) {
  const { error, result } = ctx;
  if (error) {
    return util.appendError(error.message, error.type, result);
  }
  return rds.toJsonObject(result)[0][0];
}
```

Ora prova un aggiornamento con una condizione:

```
mutation UPDATE {
  updateTodo(
    input: {
        id: 1, description: "edits: make a change", due: "2023-12-12"},
    condition: {
        description: {beginsWith: "edits"}, due: {ge: "2023-11-08"}})
    {
          description
          due
          id
        }
}
```

### Mutazione. deleteToDo
<a name="deletetodo"></a>

Puoi farlo `delete` con la mutazione. `Todo` `deleteTodo` Funziona come la `updateTodo` mutazione ed è necessario specificare `id` l'elemento che si desidera eliminare come segue.

```
mutation DELETE {
  deleteTodo(input: {id: 1}) {
    description
    due
    id
  }
}
```

### Scrittura di interrogazioni personalizzate
<a name="writing-custom-queries"></a>

Abbiamo usato le utilità del `rds` modulo per creare le nostre istruzioni SQL. Possiamo anche scrivere la nostra dichiarazione statica personalizzata per interagire con il nostro database. Innanzitutto, aggiorna lo schema per rimuovere il `id` campo dall'`CreateTask`input.

```
input CreateTaskInput {
    todoId: Int!
    description: String
}
```

Quindi, crea un paio di attività. Un'attività ha una relazione a chiave esterna con `Todo` la seguente.

```
mutation TASKS {
  a: createTask(input: {todoId: 2, description: "my first sub task"}) { id }
  b:createTask(input: {todoId: 2, description: "another sub task"}) { id }
  c: createTask(input: {todoId: 2, description: "a final sub task"}) { id }
}
```

Crea un nuovo campo nel tuo `Query` tipo chiamato `getTodoAndTasks` come segue.

```
getTodoAndTasks(id: Int!): Todo
```

Aggiungi un `tasks` campo al `Todo` tipo come segue.

```
type Todo {
    due: AWSDate!
    id: Int!
    createdAt: String
    description: String!
    tasks:TaskConnection
}
```

Salvare lo schema. Dall'editor di schemi nella console, sul lato destro, scegli **Attach Resolver for**. `getTodosAndTasks(id: Int!): Todo` Scegli la tua fonte di dati Amazon RDS. Aggiorna il tuo resolver con il seguente codice.

```
import { sql, createPgStatement,toJsonObject } from '@aws-appsync/utils/rds';

export function request(ctx) {
    return createPgStatement(
        sql`SELECT * from todos where id = ${ctx.args.id}`,
        sql`SELECT * from tasks where "todoId" = ${ctx.args.id}`);
}

export function response(ctx) {
    const result = toJsonObject(ctx.result);
    const todo = result[0][0];
    if (!todo) {
        return null;
    }
    todo.tasks = { items: result[1] };
    return todo;
}
```

In questo codice, utilizziamo il modello di `sql` tag per scrivere un'istruzione SQL a cui possiamo passare in sicurezza un valore dinamico in fase di esecuzione. `createPgStatement`può richiedere fino a due richieste SQL alla volta. Lo usiamo per inviare una richiesta per la nostra `todo` e un'altra per la nostra`tasks`. Avresti potuto farlo con una `JOIN` dichiarazione o con qualsiasi altro metodo. L'idea è quella di poter scrivere la propria istruzione SQL per implementare la logica aziendale. Per utilizzare la query nell'editor **Queries**, procedi come segue.

```
query TodoAndTasks {
  getTodosAndTasks(id: 2) {
    id
    due
    description
    tasks {
      items {
        id
        description
      }
    }
  }
}
```

## Eliminazione del cluster
<a name="rds-delete-cluster"></a>

**Importante**  
L'eliminazione di un cluster è permanente. Esamina attentamente il tuo progetto prima di eseguire questa azione.

Per eliminare il cluster:

```
$ aws rds delete-db-cluster \
    --db-cluster-identifier appsync-tutorial \
    --skip-final-snapshot
```