

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

# VTL-Resolver-Tutorials für AWS AppSync
<a name="tutorials"></a>

**Anmerkung**  
Wir unterstützen jetzt hauptsächlich die APPSYNC\$1JS-Laufzeit und ihre Dokumentation. [Bitte erwägen Sie, die APPSYNC\$1JS-Laufzeit und ihre Anleitungen hier zu verwenden.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

Datenquellen und Resolver werden verwendet, AWS AppSync um GraphQL-Anfragen zu übersetzen und Informationen aus Ihren Ressourcen abzurufen. AWS AWS AppSync unterstützt die automatische Bereitstellung und Verbindungen mit bestimmten Datenquellentypen. AWS AppSync unterstützt AWS Lambda auch Amazon DynamoDB, relationale Datenbanken (Amazon Aurora Serverless), Amazon OpenSearch Service und HTTP-Endpunkte als Datenquellen. Sie können eine GraphQL-API mit Ihren vorhandenen AWS Ressourcen verwenden oder Datenquellen und Resolver von Grund auf neu erstellen. Die folgenden Abschnitte sollen einige der gängigsten GraphQL-Anwendungsfälle in Form von Tutorials erläutern.

AWS AppSync verwendet in Apache Velocity Template Language (VTL) geschriebene *Mapping-Vorlagen* für Resolver. Weitere Informationen zur Verwendung von Mapping-Vorlagen finden Sie in der Referenz zu [Resolver-Mapping-Vorlagen](resolver-mapping-template-reference.md#aws-appsync-resolver-mapping-template-reference). Weitere Informationen zur Arbeit mit VTL finden Sie im Programmierleitfaden für [Resolver-Mapping-Vorlagen](resolver-mapping-template-reference-programming-guide.md#aws-appsync-resolver-mapping-template-reference-programming-guide).

AWS AppSync unterstützt die automatische Bereitstellung von DynamoDB-Tabellen aus einem GraphQL-Schema, wie unter Bereitstellung aus Schema (optional) und Beispielschema starten beschrieben. Sie können auch aus einer vorhandenen DynamoDB-Tabelle importieren, wodurch das Schema erstellt wird und Resolver verbunden werden. Dies wird unter Import aus Amazon DynamoDB (optional) beschrieben.

**Topics**
+ [Erstellen einer einfachen Post-Anwendung mit DynamoDB-Resolvern](tutorial-dynamodb-resolvers.md)
+ [Verwenden von Resolvern AWS Lambda](tutorial-lambda-resolvers.md)
+ [Verwenden von OpenSearch Service-Resolvern](tutorial-elasticsearch-resolvers.md)
+ [Verwendung lokaler Resolver](tutorial-local-resolvers.md)
+ [Kombinieren von GraphQL-Resolvern](tutorial-combining-graphql-resolvers.md)
+ [Verwenden von DynamoDB-Batchoperationen](tutorial-dynamodb-batch.md)
+ [DynamoDB-Transaktionen durchführen](tutorial-dynamodb-transact.md)
+ [Verwendung von HTTP-Resolvern](tutorial-http-resolvers.md)
+ [Verwenden von Aurora Serverless v2-Resolvern](tutorial-rds-resolvers.md)
+ [Verwendung von Pipeline-Resolvern](tutorial-pipeline-resolvers.md)
+ [Verwenden von Delta Sync-Vorgängen für versionierte Datenquellen](tutorial-delta-sync.md)

# Erstellen einer einfachen Post-Anwendung mit DynamoDB-Resolvern
<a name="tutorial-dynamodb-resolvers"></a>

**Anmerkung**  
Wir unterstützen jetzt hauptsächlich die APPSYNC\$1JS-Laufzeit und ihre Dokumentation. [Bitte erwägen Sie, die APPSYNC\$1JS-Laufzeit und ihre Anleitungen hier zu verwenden.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

Dieses Tutorial zeigt, wie Sie Ihre eigenen Amazon DynamoDB-Tabellen mit einer GraphQL-API verbinden können. AWS AppSync 

Sie können DynamoDB-Ressourcen in Ihrem Namen AWS AppSync bereitstellen lassen. Alternativ können Sie auch vorhandene Tabellen mit einem GraphQL-Schema verbinden, indem Sie eine Datenquelle und einen Resolver erstellen. In beiden Fällen können Sie Lese- und Schreibvorgänge in Ihrer DynamoDB-Datenbank über GraphQL-Anweisungen ausführen – und Echtzeit-Daten abonnieren.

Es müssen bestimmte Konfigurationsschritte ausgeführt werden, damit GraphQL-Anweisungen in DynamoDB-Operationen und die Antworten wieder in GraphQL übersetzt werden können. In diesem Tutorial wird der Konfigurationsprozess anhand mehrerer Szenarien und Datenzugriffsmuster aus der Praxis veranschaulicht.

## DynamoDB-Tabellen einrichten
<a name="setting-up-your-ddb-tables"></a>

Um mit diesem Tutorial zu beginnen, müssen Sie zunächst die folgenden Schritte ausführen, um Ressourcen bereitzustellen AWS .

1. Stellen Sie AWS Ressourcen mithilfe der folgenden AWS CloudFormation Vorlage in der CLI bereit:

   ```
   aws cloudformation create-stack \
       --stack-name AWSAppSyncTutorialForAmazonDynamoDB \
       --template-url https://s3.us-west-2.amazonaws.com/awsappsync/resources/dynamodb/AmazonDynamoDBCFTemplate.yaml \
       --capabilities CAPABILITY_NAMED_IAM
   ```

   Alternativ können Sie den folgenden CloudFormation Stack in der Region US-West 2 (Oregon) in Ihrem AWS Konto starten.

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

   Dadurch wird Folgendes erstellt:
   + Eine DynamoDB-Tabelle namens`AppSyncTutorial-Post`, die Daten enthalten `Post` wird.
   + Eine IAM-Rolle und die zugehörige, von IAM verwaltete Richtlinie, um die Interaktion mit der Tabelle AWS AppSync zu ermöglichen. `Post`

1. Wenn Sie weitere Informationen zum Stack und den erstellten Ressourcen benötigen, führen Sie den folgenden CLI-Befehl aus:

   ```
   aws cloudformation describe-stacks --stack-name AWSAppSyncTutorialForAmazonDynamoDB
   ```

1. Wenn Sie die Ressourcen später löschen möchten, führen Sie folgenden Befehl aus:

   ```
   aws cloudformation delete-stack --stack-name AWSAppSyncTutorialForAmazonDynamoDB
   ```

## Erstellen Sie Ihre GraphQL-API
<a name="creating-your-graphql-api"></a>

Um die GraphQL-API zu erstellen in AWS AppSync:

1. Melden Sie sich bei der an AWS-Managementkonsole und öffnen Sie die [AppSync Konsole](https://console.aws.amazon.com/appsync/).

   1. Wählen Sie im **APIs Dashboard** **Create API** aus.

1. Wählen **Sie im Fenster Passen Sie Ihre API an oder importieren Sie aus Amazon DynamoDB** die Option **Von Grund auf neu erstellen**.

   1. Wählen Sie rechts neben demselben Fenster **Start** aus.

1. Stellen Sie im Feld **API-Name** den Namen der API auf ein`AWSAppSyncTutorial`.

1. Wählen Sie **Erstellen** aus.

Die AWS AppSync Konsole erstellt mithilfe des API-Schlüsselauthentifizierungsmodus eine neue GraphQL-API für Sie. Sie können in der Konsole den Rest der GraphQL-API einrichten und im weiteren Verlauf dieses Tutorials abfragen.

## Definition einer grundlegenden Post-API
<a name="defining-a-basic-post-api"></a>

Nachdem Sie eine AWS AppSync GraphQL-API erstellt haben, können Sie ein grundlegendes Schema einrichten, das das grundlegende Erstellen, Abrufen und Löschen von Post-Daten ermöglicht.

1. [Melden Sie sich bei der an AWS-Managementkonsole und öffnen Sie die AppSync Konsole.](https://console.aws.amazon.com/appsync/)

   1. Wählen Sie im **APIs Dashboard** die API aus, die Sie gerade erstellt haben.

1. Wählen Sie in der **Seitenleiste** **Schema** aus.

   1. Ersetzen Sie im **Schemabereich** den Inhalt durch den folgenden Code:

     ```
     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. Wählen Sie **Speichern**.

Dieses Schema definiert einen `Post`-Typ und Operationen zum Hinzufügen und Abrufen von `Post`-Objekten.

## Konfiguration der Datenquelle für die DynamoDB-Tabellen
<a name="configuring-the-data-source-for-the-ddb-tables"></a>

Verknüpfen Sie als Nächstes die im Schema definierten Abfragen und Mutationen mit der `AppSyncTutorial-Post` DynamoDB-Tabelle.

Zunächst AWS AppSync müssen Sie sich Ihrer Tabellen bewusst sein. Hierzu richten Sie eine Datenquelle in AWS AppSync ein:

1. Melden Sie sich bei der an AWS-Managementkonsole und öffnen Sie die [AppSync Konsole](https://console.aws.amazon.com/appsync/).

   1. Wählen Sie im **APIs Dashboard** Ihre GraphQL-API aus.

   1. Wählen Sie in der **Seitenleiste** **Datenquellen** aus.

1. Klicken Sie auf **Create data source**.

   1. Geben Sie als **Namen der Datenquelle** in `PostDynamoDBTable` ein. 

   1. Wählen Sie als **Datenquellentyp** **Amazon DynamoDB-Tabelle** aus.

   1. **Wählen Sie für **Region US-WEST-2** aus.**

   1. Wählen Sie als **Tabellenname** die DynamoDB-Tabelle **AppSyncTutorial-Post** aus.

   1. Erstellen Sie eine neue IAM-Rolle (empfohlen) oder wählen Sie eine vorhandene Rolle aus, die über die IAM-Berechtigung verfügt. `lambda:invokeFunction` Für bestehende Rollen ist eine Vertrauensrichtlinie erforderlich, wie im Abschnitt [Eine Datenquelle anhängen](attaching-a-data-source.md) beschrieben. 

      Im Folgenden finden Sie ein Beispiel für eine IAM-Richtlinie, die über die erforderlichen Berechtigungen für die Ausführung von Vorgängen auf der Ressource verfügt:

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

****  

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

------

1. Wählen Sie **Erstellen** aus.

## Den AddPost-Resolver einrichten (DynamoDB) PutItem
<a name="setting-up-the-addpost-resolver-dynamodb-putitem"></a>

**Nachdem AWS AppSync Sie die DynamoDB-Tabelle erkannt haben, können Sie sie mit einzelnen Abfragen und Mutationen verknüpfen, indem Sie Resolver definieren.** Der erste Resolver, den Sie erstellen, ist der `addPost` Resolver, mit dem Sie einen Beitrag in der `AppSyncTutorial-Post` DynamoDB-Tabelle erstellen können.

Resolver bestehen aus folgenden Komponenten:
+ Die Stelle im GraphQL-Schema, an der der Resolver angefügt werden soll. In diesem Fall richten Sie einen Resolver im Feld `addPost` im Typ `Mutation` ein. Diesen Resolver können Sie mit `mutation { addPost(...){...} }` aufrufen.
+ Die Datenquelle für diesen Resolver. In diesem Fall soll die zuvor definierte Datenquelle `PostDynamoDBTable` verwendet werden, damit Sie Einträge in der DynamoDB-Tabelle `AppSyncTutorial-Post` hinzufügen können.
+ Die Zuweisungsvorlage für Anforderungen. Der Zweck der Vorlage für die Anforderungszuweisung besteht darin, die eingehende Anfrage des Aufrufers entgegenzunehmen und sie in Anweisungen zur Ausführung gegen DynamoDB AWS AppSync zu übersetzen.
+ Die Zuweisungsvorlage für Antworten. Eine Zuweisungsvorlage für Antworten übersetzt die Antwort aus DynamoDB zurück in eine Eingabe, die GraphQL erwartet. Dies ist nützlich, wenn sich das Format der Daten in DynamoDB vom `Post`-Typ in GraphQL unterscheidet. In diesem Fall stimmt die Form jedoch überein, daher werden die Daten direkt übergeben.

Richten Sie den Resolver wie folgt ein:

1. [Melden Sie sich bei der an AWS-Managementkonsole und öffnen Sie die Konsole. AppSync ](https://console.aws.amazon.com/appsync/)

   1. Wählen Sie im **APIs Dashboard** Ihre GraphQL-API aus.

   1. Wählen Sie in der **Seitenleiste** **Datenquellen** aus.

1. Klicken Sie auf **Create data source**.

   1. Geben Sie als **Namen der Datenquelle** in `PostDynamoDBTable` ein. 

   1. Wählen Sie als **Datenquellentyp** **Amazon DynamoDB-Tabelle** aus.

   1. **Wählen Sie für **Region US-WEST-2** aus.**

   1. Wählen Sie als **Tabellenname** die DynamoDB-Tabelle **AppSyncTutorial-Post** aus.

   1. Erstellen Sie eine neue IAM-Rolle (empfohlen) oder wählen Sie eine vorhandene Rolle aus, die über die IAM-Berechtigung verfügt. `lambda:invokeFunction` Für bestehende Rollen ist eine Vertrauensrichtlinie erforderlich, wie im Abschnitt [Eine Datenquelle anhängen](attaching-a-data-source.md) beschrieben. 

      Im Folgenden finden Sie ein Beispiel für eine IAM-Richtlinie, die über die erforderlichen Berechtigungen für die Ausführung von Vorgängen auf der Ressource verfügt:

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

****  

      ```
      { 
           "Version":"2012-10-17",		 	 	  
           "Statement": [ 
               { 
                   "Effect": "Allow", 
                   "Action": [ "lambda:invokeFunction" ], 
                   "Resource": [ 
                       "arn:aws:lambda:us-west-2:123456789012:function:myFunction", 
                       "arn:aws:lambda:us-west-2:123456789012:function:myFunction:*" 
                   ] 
               } 
           ] 
       }
      ```

------

1. Wählen Sie **Erstellen** aus.

1. Wählen Sie die Registerkarte **Schema** aus.

1. Suchen Sie rechts im Bereich **Data types (Datentypen)** das Feld **addPost** des Typs **Mutation** und wählen Sie dann **Attach (Anhängen)**.

1. Wählen Sie im **Menü Aktion** die Option **Laufzeit aktualisieren** und anschließend **Unit Resolver (nur VTL**) aus.

1. Wählen Sie für **Data source name (Datenquellenname)** die Option **PostDynamoDBTable** aus.

1. Fügen Sie unter **Configure the request mapping template (Zuweisungsvorlage für Anforderungen konfigurieren)** Folgendes ein:

   ```
   {
       "version" : "2017-02-28",
       "operation" : "PutItem",
       "key" : {
           "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
       },
       "attributeValues" : {
           "author" : $util.dynamodb.toDynamoDBJson($context.arguments.author),
           "title" : $util.dynamodb.toDynamoDBJson($context.arguments.title),
           "content" : $util.dynamodb.toDynamoDBJson($context.arguments.content),
           "url" : $util.dynamodb.toDynamoDBJson($context.arguments.url),
           "ups" : { "N" : 1 },
           "downs" : { "N" : 0 },
           "version" : { "N" : 1 }
       }
   }
   ```

   **Hinweis:** Für alle Schlüssel und Attributwerte wird ein *Typ* angegeben. So legen Sie beispielsweise das Feld `author` auf `{ "S" : "${context.arguments.author}" }` fest. Der `S` Teil gibt an AWS AppSync und DynamoDB an, dass der Wert ein Zeichenkettenwert sein wird. Der tatsächliche Wert wird aus dem `author`-Argument eingefügt. Das Feld `version` ist ein Zahlenfeld, da als Typ `N` verwendet wird. Schließlich initialisieren Sie auch die Felder `ups`, `downs` und `version`.

   Für dieses Tutorial haben Sie angegeben, dass der `ID!` GraphQL-Typ, der das neue Element, das in DynamoDB eingefügt wird, indexiert, Teil der Client-Argumente ist. AWS AppSync enthält ein Hilfsprogramm zur automatischen ID-Generierung namens`$utils.autoId()`, das Sie auch in der Form von hätten verwenden können. `"id" : { "S" : "${$utils.autoId()}" }` Dann würden Sie `id: ID!` nicht in der Schemadefinition von `addPost()` angeben, sondern die ID würde automatisch eingefügt. Sie werden diese Technik in diesem Tutorial nicht verwenden, sollten sie jedoch als bewährte Methode beim Schreiben in DynamoDB-Tabellen betrachten.

   Weitere Informationen zu Lambda-Zuweisungsvorlagen finden Sie in der Referenzdokumentation [Übersicht über die Resolver-Zuweisungsvorlage](resolver-mapping-template-reference-overview.md#aws-appsync-resolver-mapping-template-reference-overview). Weitere Informationen zur GetItem Anforderungszuordnung finden Sie in der [GetItem](aws-appsync-resolver-mapping-template-reference-dynamodb-getitem.md)Referenzdokumentation. Weitere Informationen zu Typen enthält die Referenzdokumentation [Typsystem (Anforderungszuweisung)](aws-appsync-resolver-mapping-template-reference-dynamodb-typed-values-request.md).

1. Fügen Sie unter **Configure the response mapping template (Zuweisungsvorlage für Antworten konfigurieren)** Folgendes ein:

   ```
   $utils.toJson($context.result)
   ```

    **Hinweis:** Da das Format der Daten in der Tabelle `AppSyncTutorial-Post` genau mit dem Format des `Post`-Typs in GraphQL übereinstimmt, übergibt die Zuweisungsvorlage für die Antwort die Ergebnisse einfach direkt. Beachten Sie auch, dass in allen Beispielen in diesem Tutorial die gleiche Zuweisungsvorlage für Antworten verwendet wird, sodass Sie nur eine Datei erstellen müssen.

1. Wählen Sie **Speichern**.

### Aufrufen der API zum Hinzufügen eines Posts
<a name="call-the-api-to-add-a-post"></a>

Jetzt, da der Resolver eingerichtet ist, AWS AppSync kann er eine eingehende `addPost` Mutation in eine PutItem DynamoDB-Operation übersetzen. Sie können jetzt eine Mutation ausführen, um Inhalte in der Tabelle hinzuzufügen.
+ Wählen Sie die Registerkarte **Queries** aus.
+ Fügen Sie die folgende Mutation in den Bereich **Queries (Abfragen)** ein:

  ```
  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
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).
+ Die Ergebnisse des neu erstellten Posts sollten im Ergebnisbereich rechts neben dem Abfragebereich angezeigt werden. Das sollte bei Ihnen ähnlich wie im folgenden Bild aussehen:

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

Folgendes wurden ausgeführt:
+ AWS AppSync hat eine Mutationsanfrage erhalten. `addPost`
+ AWS AppSync hat die Anfrage und die Vorlage für die Anforderungszuweisung entgegengenommen und ein Dokument zur Anforderungszuweisung generiert. Dies sieht wie folgt aus:

  ```
  {
      "version" : "2017-02-28",
      "operation" : "PutItem",
      "key" : {
          "id" : { "S" : "123" }
      },
      "attributeValues" : {
          "author": { "S" : "AUTHORNAME" },
          "title": { "S" : "Our first post!" },
          "content": { "S" : "This is our first post." },
          "url": { "S" : "https://aws.amazon.com/appsync/" },
          "ups" : { "N" : 1 },
          "downs" : { "N" : 0 },
          "version" : { "N" : 1 }
      }
  }
  ```
+ AWS AppSync hat das Anforderungszuordnungsdokument verwendet, um eine `PutItem` DynamoDB-Anforderung zu generieren und auszuführen.
+ AWS AppSync nahm die Ergebnisse der `PutItem` Anfrage und konvertierte sie wieder in GraphQL-Typen.

  ```
  {
      "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
  }
  ```
+ Dann wurden sie über das Antwortzuweisungsdokument unverändert weiter übergeben.
+ Das neu erstellte Objekt wurde in der GraphQL-Antwort zurückgegeben.

## Einrichtung des GetPost-Resolvers (DynamoDB) GetItem
<a name="setting-up-the-getpost-resolver-ddb-getitem"></a>

Jetzt, da Sie der `AppSyncTutorial-Post` DynamoDB-Tabelle Daten hinzufügen können, müssen Sie die `getPost` Abfrage so einrichten, dass sie diese Daten aus der `AppSyncTutorial-Post` Tabelle abrufen kann. Hierzu richten Sie einen weiteren Resolver ein.
+ Wählen Sie die Registerkarte **Schema** aus.
+ Suchen Sie rechts im Bereich **Data types (Datentypen)** das Feld **getPost** des Typs **Query (Abfrage)** und wählen Sie dann **Attach (Anhängen)**.
+ Wählen Sie im **Menü Aktion** die Option **Laufzeit aktualisieren** und anschließend **Unit Resolver (nur VTL**) aus.
+ Wählen Sie für **Data source name (Datenquellenname)** die Option **PostDynamoDBTable** aus.
+ Fügen Sie unter **Configure the request mapping template (Zuweisungsvorlage für Anforderungen konfigurieren)** Folgendes ein:

  ```
  {
      "version" : "2017-02-28",
      "operation" : "GetItem",
      "key" : {
          "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)
      }
  }
  ```
+ Fügen Sie unter **Configure the response mapping template (Zuweisungsvorlage für Antworten konfigurieren)** Folgendes ein:

  ```
  $utils.toJson($context.result)
  ```
+ Wählen Sie **Speichern**.

### Aufrufen der API zum Abrufen eines Posts
<a name="call-the-api-to-get-a-post"></a>

Jetzt ist der Resolver eingerichtet und AWS AppSync weiß, wie man eine eingehende `getPost` Abfrage in eine `GetItem` DynamoDB-Operation übersetzt. Sie können jetzt eine Abfrage ausführen, um den zuvor erstellten Post abzurufen.
+ Wählen Sie die Registerkarte **Queries** aus.
+ Fügen Sie im Bereich **Abfragen** Folgendes ein:

  ```
  query getPost {
    getPost(id:123) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).
+ Der von DynamoDB abgerufene Beitrag sollte im Ergebnisbereich rechts neben dem Abfragebereich angezeigt werden. Das sollte bei Ihnen ähnlich wie im folgenden Bild aussehen:

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

Folgendes wurden ausgeführt:
+ AWS AppSync hat eine `getPost` Abfrageanforderung erhalten.
+ AWS AppSync hat die Anfrage und die Vorlage für die Anforderungszuweisung entgegengenommen und ein Dokument zur Anforderungszuweisung generiert. Dies sieht wie folgt aus:

  ```
  {
      "version" : "2017-02-28",
      "operation" : "GetItem",
      "key" : {
          "id" : { "S" : "123" }
      }
  }
  ```
+ AWS AppSync hat das Anforderungszuordnungsdokument verwendet, um eine GetItem DynamoDB-Anforderung zu generieren und auszuführen.
+ AWS AppSync nahm die Ergebnisse der `GetItem` Anfrage und konvertierte sie wieder in GraphQL-Typen.

  ```
  {
      "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
  }
  ```
+ Dann wurden sie über das Antwortzuweisungsdokument unverändert weiter übergeben.
+ Das abgerufene Objekt wurde in der Antwort zurückgegeben.

Nehmen Sie alternativ das folgende Beispiel:

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

Wenn Ihre `getPost` Abfrage nur das`id`, und benötigt`author`, können Sie Ihre Anforderungszuordnungsvorlage so ändern`title`, dass Projektionsausdrücke verwendet werden, um nur die gewünschten Attribute aus Ihrer DynamoDB-Tabelle anzugeben, um unnötige Datenübertragungen von DynamoDB zu zu zu vermeiden. AWS AppSync Die Vorlage für die Anforderungszuweisung könnte beispielsweise wie der folgende Ausschnitt aussehen:

```
{
    "version" : "2017-02-28",
    "operation" : "GetItem",
    "key" : {
        "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)
    },
    "projection" : {
     "expression" : "#author, id, title",
     "expressionNames" : { "#author" : "author"}
    }
}
```

## Eine UpdatePost-Mutation erstellen (DynamoDB) UpdateItem
<a name="create-an-updatepost-mutation-ddb-updateitem"></a>

Bisher können Sie `Post` Objekte in DynamoDB erstellen und abrufen. Als Nächstes richten Sie eine neue Mutation ein, um ein Objekt zu aktualisieren. Dazu verwenden Sie die UpdateItem DynamoDB-Operation.
+ Wählen Sie die Registerkarte **Schema** aus.
+ Ändern Sie im **Schemabereich** den `Mutation` Typ, um eine neue `updatePost` Mutation hinzuzufügen, wie folgt:

  ```
  type Mutation {
      updatePost(
          id: ID!,
          author: String!,
          title: String!,
          content: String!,
          url: String!
      ): Post
      addPost(
          author: String!
          title: String!
          content: String!
          url: String!
      ): Post!
  }
  ```
+ Wählen Sie **Speichern**.
+ Suchen Sie rechts im Bereich **Data types (Datentypen)** das neue Feld **updatePost** des Typs **Mutation** und wählen Sie dann **Attach (Anhängen)**.
+ Wählen Sie im **Menü Aktion** die Option **Laufzeit aktualisieren** und anschließend **Unit Resolver (nur VTL**) aus.
+ Wählen Sie für **Data source name (Datenquellenname)** die Option **PostDynamoDBTable** aus.
+ Fügen Sie unter **Configure the request mapping template (Zuweisungsvorlage für Anforderungen konfigurieren)** Folgendes ein:

  ```
  {
      "version" : "2017-02-28",
      "operation" : "UpdateItem",
      "key" : {
          "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
      },
      "update" : {
          "expression" : "SET author = :author, title = :title, content = :content, #url = :url ADD version :one",
          "expressionNames": {
              "#url" : "url"
          },
          "expressionValues": {
              ":author" : $util.dynamodb.toDynamoDBJson($context.arguments.author),
              ":title" : $util.dynamodb.toDynamoDBJson($context.arguments.title),
              ":content" : $util.dynamodb.toDynamoDBJson($context.arguments.content),
              ":url" : $util.dynamodb.toDynamoDBJson($context.arguments.url),
              ":one" : { "N": 1 }
          }
      }
  }
  ```

   **Hinweis:** Dieser Resolver verwendet DynamoDB UpdateItem, was sich erheblich von der Operation unterscheidet. PutItem Anstatt das gesamte Element zu schreiben, bitten Sie DynamoDB lediglich, bestimmte Attribute zu aktualisieren. Dies erfolgt mithilfe von DynamoDB-Aktualisierungsausdrücken. Der Ausdruck selbst wird im Feld `expression` im Abschnitt `update` angegeben. Er gibt an, dass die Attribute `author`, `title`, `content` und "url" festgelegt werden sollen und dann das Feld `version` inkrementiert werden soll. Die zu verwendenden Werte werden nicht im Ausdruck selbst angegeben. Der Ausdruck enthält Platzhalter, deren Namen mit einem Doppelpunkt beginnen. Diese werden dann im Feld `expressionValues` definiert. Schließlich hat DynamoDB reservierte Wörter, die nicht in der vorkommen dürfen. `expression` `url` ist beispielsweise ein reservierter Begriff. Zum Aktualisieren des Felds `url` können Sie daher Platzhalter für Namen verwenden und sie im Feld `expressionNames` definieren.

  Weitere Informationen zur `UpdateItem` Anforderungszuordnung finden Sie in der [UpdateItem](aws-appsync-resolver-mapping-template-reference-dynamodb-updateitem.md)Referenzdokumentation. Weitere Informationen zum Schreiben von Aktualisierungsausdrücken finden Sie in der [DynamoDB-Dokumentation UpdateExpressions ](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html).
+ Fügen Sie unter **Configure the response mapping template (Zuweisungsvorlage für Antworten konfigurieren)** Folgendes ein:

  ```
  $utils.toJson($context.result)
  ```

### Aufrufen der API zum Aktualisieren eines Posts
<a name="call-the-api-to-update-a-post"></a>

Jetzt ist der Resolver eingerichtet und AWS AppSync weiß, wie man eine eingehende `update` Mutation in eine `Update` DynamoDB-Operation übersetzt. Sie können jetzt eine Mutation ausführen, um das zuvor geschriebene Element zu aktualisieren.
+ Wählen Sie die Registerkarte **Queries** aus.
+ Fügen Sie die folgende Mutation in den Bereich **Queries (Abfragen)** ein. Außerdem müssen Sie das `id`-Argument mit dem zuvor notierten Wert aktualisieren.

  ```
  mutation updatePost {
    updatePost(
      id:"123"
      author: "A new author"
      title: "An updated author!"
      content: "Now with updated content!"
      url: "https://aws.amazon.com/appsync/"
    ) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).
+ Der aktualisierte Beitrag in DynamoDB sollte im Ergebnisbereich rechts neben dem Abfragebereich angezeigt werden. Das sollte bei Ihnen ähnlich wie im folgenden Bild aussehen:

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

In diesem Beispiel wurden die `downs` Felder `ups` und nicht geändert, da die Vorlage für die Anforderungszuweisung DynamoDB nicht AWS AppSync aufforderte, irgendetwas mit diesen Feldern zu tun. Außerdem wurde das `version` Feld um 1 erhöht, weil Sie DynamoDB gebeten AWS AppSync haben, dem Feld 1 hinzuzufügen. `version`

## Ändern des UpdatePost-Resolvers (DynamoDB) UpdateItem
<a name="modifying-the-updatepost-resolver-dynamodb-updateitem"></a>

Dies war ein erfolgreicher Start für die `updatePost`-Mutation, es gibt aber zwei wesentliche Probleme:
+ Auch wenn nur ein einzelnes Feld aktualisiert werden soll, müssen alle Felder aktualisiert werden.
+ Wenn zwei Benutzer das Objekt ändern, können Informationen verloren gehen.

Um diese Probleme zu beheben, ändern wir die `updatePost`-Mutation so, dass nur Argumente geändert werden, die in der Anforderung angegeben wurden. Dann fügen wir der `UpdateItem`-Operation eine Bedingung hinzu.

1. Wählen Sie die Registerkarte **Schema** aus.

1. Ändern Sie im Bereich **Schema** das Feld `updatePost` im Typ `Mutation`, um die Ausrufungszeichen aus den Argumenten `author`, `title`, `content` und `url` zu entfernen. Achten Sie dabei darauf, das Feld `id` nicht zu ändern. Hierdurch werden die Argumente optional. Fügen Sie außerdem ein neues erforderliches `expectedVersion`-Argument hinzu.

   ```
   type Mutation {
       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. Wählen Sie **Speichern**.

1. Suchen Sie im Bereich **Data types (Datentypen)** auf der rechten Seite das Feld **updatePost** des Typs **Mutation**.

1. Wählen Sie, ob der vorhandene Resolver geöffnet **PostDynamoDBTable**werden soll.

1. Ändern Sie unter **Configure the request mapping template (Zuweisungsvorlage für Anforderungen konfigurieren)** folgendermaßen die Anforderungszuweisungsvorlage:

   ```
   {
       "version" : "2017-02-28",
       "operation" : "UpdateItem",
       "key" : {
           "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
       },
   
       ## Set up some space to keep track of things you're updating **
       #set( $expNames  = {} )
       #set( $expValues = {} )
       #set( $expSet = {} )
       #set( $expAdd = {} )
       #set( $expRemove = [] )
   
       ## Increment "version" by 1 **
       $!{expAdd.put("version", ":one")}
       $!{expValues.put(":one", { "N" : 1 })}
   
       ## Iterate through each argument, skipping "id" and "expectedVersion" **
       #foreach( $entry in $context.arguments.entrySet() )
           #if( $entry.key != "id" && $entry.key != "expectedVersion" )
               #if( (!$entry.value) && ("$!{entry.value}" == "") )
                   ## If the argument is set to "null", then remove that attribute from the item in DynamoDB **
   
                   #set( $discard = ${expRemove.add("#${entry.key}")} )
                   $!{expNames.put("#${entry.key}", "$entry.key")}
               #else
                   ## Otherwise set (or update) the attribute on the item in DynamoDB **
   
                   $!{expSet.put("#${entry.key}", ":${entry.key}")}
                   $!{expNames.put("#${entry.key}", "$entry.key")}
                   $!{expValues.put(":${entry.key}", { "S" : "${entry.value}" })}
               #end
           #end
       #end
   
       ## Start building the update expression, starting with attributes you're going to SET **
       #set( $expression = "" )
       #if( !${expSet.isEmpty()} )
           #set( $expression = "SET" )
           #foreach( $entry in $expSet.entrySet() )
               #set( $expression = "${expression} ${entry.key} = ${entry.value}" )
               #if ( $foreach.hasNext )
                   #set( $expression = "${expression}," )
               #end
           #end
       #end
   
       ## Continue building the update expression, adding attributes you're going to ADD **
       #if( !${expAdd.isEmpty()} )
           #set( $expression = "${expression} ADD" )
           #foreach( $entry in $expAdd.entrySet() )
               #set( $expression = "${expression} ${entry.key} ${entry.value}" )
               #if ( $foreach.hasNext )
                   #set( $expression = "${expression}," )
               #end
           #end
       #end
   
       ## Continue building the update expression, adding attributes you're going to REMOVE **
       #if( !${expRemove.isEmpty()} )
           #set( $expression = "${expression} REMOVE" )
   
           #foreach( $entry in $expRemove )
               #set( $expression = "${expression} ${entry}" )
               #if ( $foreach.hasNext )
                   #set( $expression = "${expression}," )
               #end
           #end
       #end
   
       ## Finally, write the update expression into the document, along with any expressionNames and expressionValues **
       "update" : {
           "expression" : "${expression}"
           #if( !${expNames.isEmpty()} )
               ,"expressionNames" : $utils.toJson($expNames)
           #end
           #if( !${expValues.isEmpty()} )
               ,"expressionValues" : $utils.toJson($expValues)
           #end
       },
   
       "condition" : {
           "expression"       : "version = :expectedVersion",
           "expressionValues" : {
               ":expectedVersion" : $util.dynamodb.toDynamoDBJson($context.arguments.expectedVersion)
           }
       }
   }
   ```

1. Wählen Sie **Speichern**.

Diese Vorlage ist eines der komplexeren Beispiele. Es zeigt die Leistung und Flexibilität der Zuweisungsvorlagen. Es durchläuft alle Argumente und springt dann zu `id` und `expectedVersion`. Wenn das Argument auf etwas gesetzt ist, fordert AWS AppSync es DynamoDB auf, dieses Attribut für das Objekt in DynamoDB zu aktualisieren. Wenn das Attribut auf Null gesetzt ist, fordert AWS AppSync es DynamoDB auf, dieses Attribut aus dem Post-Objekt zu entfernen. Wenn ein Argument nicht angegeben wurde, wird das Attribut nicht geändert. Außerdem wird das Feld `version` inkrementiert.

Außerdem gibt es einen neuen `condition`-Abschnitt. Ein Bedingungsausdruck ermöglicht es Ihnen AWS AppSync , DynamoDB anhand des Status des Objekts, das sich bereits vor der Ausführung des Vorgangs in DynamoDB befand, mitzuteilen, ob die Anforderung erfolgreich sein soll oder nicht. In diesem Fall möchten Sie, dass die `UpdateItem` Anfrage nur erfolgreich ist, wenn das `version` Feld des Elements, das sich derzeit in DynamoDB befindet, genau mit dem `expectedVersion` Argument übereinstimmt.

Weitere Informationen zu Bedingungsausdrücken finden Sie in der [Bedingungsausdrücke](aws-appsync-resolver-mapping-template-reference-dynamodb-condition-expressions.md)-Referenzdokumentation.

### Aufrufen der API zum Aktualisieren eines Posts
<a name="id1"></a>

Aktualisieren wir nun unser `Post`-Objekt mit dem neuen Resolver:
+ Wählen Sie die Registerkarte **Queries** aus.
+ Fügen Sie die folgende Mutation in den Bereich **Queries (Abfragen)** ein. Außerdem müssen Sie das `id`-Argument mit dem zuvor notierten Wert aktualisieren.

  ```
  mutation updatePost {
    updatePost(
      id:123
      title: "An empty story"
      content: null
      expectedVersion: 2
    ) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).
+ Der aktualisierte Beitrag in DynamoDB sollte im Ergebnisbereich rechts neben dem Abfragebereich angezeigt werden. Das sollte bei Ihnen ähnlich wie im folgenden Bild aussehen:

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

In dieser Anfrage haben Sie DynamoDB gebeten AWS AppSync , nur das `content` Feld `title` und zu aktualisieren. Alle anderen Felder bleiben unverändert (nur das Feld `version` wird inkrementiert). Das `title`-Attribut wurde auf einen neuen Wert festgelegt und das `content`-Attribut wurde aus dem Post entfernt. Die Felder `author`, `url`, `ups` und `downs` blieben unverändert.

Führen Sie die Mutationsanforderung erneut aus und belassen Sie sie dabei unverändert. Es wird eine Antwort ähnlich der folgenden angezeigt:

```
{
  "data": {
    "updatePost": null
  },
  "errors": [
    {
      "path": [
        "updatePost"
      ],
      "data": {
        "id": "123",
        "author": "A new author",
        "title": "An empty story",
        "content": null,
        "url": "https://aws.amazon.com/appsync/",
        "ups": 1,
        "downs": 0,
        "version": 3
      },
      "errorType": "DynamoDB:ConditionalCheckFailedException",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "message": "The conditional request failed (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ConditionalCheckFailedException; Request ID: ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ)"
    }
  ]
}
```

Die Anforderung schlägt fehl, weil der Bedingungsausdruck als "false" ausgewertet wird:
+ Als Sie die Anfrage zum ersten Mal ausgeführt haben, war der Wert des `version` Felds des Beitrags in DynamoDB`2`, der `expectedVersion` dem Argument entsprach. Die Anfrage war erfolgreich, was bedeutete, dass das `version` Feld in DynamoDB auf inkrementiert wurde. `3`
+ Als Sie die Anfrage zum zweiten Mal ausgeführt haben, war der Wert des `version` Felds des Beitrags in DynamoDB`3`, der nicht mit dem `expectedVersion` Argument übereinstimmte.

Dieses Muster wird normalerweise als *optimistische Sperre* bezeichnet.

Ein Merkmal eines AWS AppSync DynamoDB-Resolvers besteht darin, dass er den aktuellen Wert des Post-Objekts in DynamoDB zurückgibt. Sie finden dies im Feld `data` im Abschnitt `errors` der GraphQL-Antwort. Ihre Anwendung kann anhand dieser Informationen entscheiden, wie weiter vorgegangen werden soll. In diesem Fall können Sie sehen, dass das `version` Feld des Objekts in DynamoDB auf `3` gesetzt ist. Sie könnten also das `expectedVersion` Argument einfach auf aktualisieren `3` und die Anfrage wäre wieder erfolgreich.

Weitere Informationen zum Behandeln von Fehlern bei Bedingungsprüfungen finden Sie in der Zuweisungsvorlagen-Referenzdokumentation für [Bedingungsausdrücke](aws-appsync-resolver-mapping-template-reference-dynamodb-condition-expressions.md).

## UpvotePost- und DownvotePost-Mutationen erstellen (DynamoDB) UpdateItem
<a name="create-upvotepost-and-downvotepost-mutations-ddb-updateitem"></a>

Der Typ `Post` verfügt über die Felder `ups` und `downs`, mit denen Upvotes und Downvotes erfasst werden können. In der API können sie allerdings derzeit nicht verwendet werden. Fügen Sie daher einige Mutationen hinzu, um Upvotes und Downvotes für die Posts zu ermöglichen.
+ Wählen Sie die Registerkarte **Schema** aus.
+ Ändern Sie im **Schemabereich** den `Mutation` Typ, um neue Mutationen hinzuzufügen, wie folgt: `upvotePost` `downvotePost`

  ```
  type Mutation {
      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!
  }
  ```
+ Wählen Sie **Speichern**.
+ Suchen Sie rechts im Bereich **Data types (Datentypen)** das neue Feld **upvotePost** des Typs **Mutation** und wählen Sie dann **Attach (Anhängen)**.
+ Wählen Sie im **Menü Aktion** die Option **Laufzeit aktualisieren** und anschließend **Unit Resolver (nur VTL**) aus.
+ Wählen Sie für **Data source name (Datenquellenname)** die Option **PostDynamoDBTable** aus.
+ Fügen Sie unter **Configure the request mapping template (Zuweisungsvorlage für Anforderungen konfigurieren)** Folgendes ein:

  ```
  {
      "version" : "2017-02-28",
      "operation" : "UpdateItem",
      "key" : {
          "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
      },
      "update" : {
          "expression" : "ADD ups :plusOne, version :plusOne",
          "expressionValues" : {
              ":plusOne" : { "N" : 1 }
          }
      }
  }
  ```
+ Fügen Sie unter **Configure the response mapping template (Zuweisungsvorlage für Antworten konfigurieren)** Folgendes ein:

  ```
  $utils.toJson($context.result)
  ```
+ Wählen Sie **Speichern**.
+ Suchen Sie rechts im Bereich **Data types (Datentypen)** das neue Feld `downvotePost` des Typs **Mutation** und wählen Sie dann **Attach (Anhängen)**.
+ Wählen Sie für **Data source name (Datenquellenname)** die Option **PostDynamoDBTable** aus.
+ Fügen Sie unter **Configure the request mapping template (Zuweisungsvorlage für Anforderungen konfigurieren)** Folgendes ein:

  ```
  {
      "version" : "2017-02-28",
      "operation" : "UpdateItem",
      "key" : {
          "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
      },
      "update" : {
          "expression" : "ADD downs :plusOne, version :plusOne",
          "expressionValues" : {
              ":plusOne" : { "N" : 1 }
          }
      }
  }
  ```
+ Fügen Sie unter **Configure the response mapping template (Zuweisungsvorlage für Antworten konfigurieren)** Folgendes ein:

  ```
  $utils.toJson($context.result)
  ```
+ Wählen Sie **Speichern**.

### Aufrufen der API für ein Upvote oder Downvote eines Posts
<a name="call-the-api-to-upvote-and-downvote-a-post"></a>

Jetzt wurden die neuen Resolver eingerichtet, AWS AppSync weiß, wie man eine eingehende Operation `upvotePost` oder eine `downvote` Mutation in eine UpdateItem DynamoDB-Operation übersetzt. Sie können jetzt Mutationen ausführen, um Upvotes oder Downvotes für den zuvor erstellten Post auszuführen.
+ Wählen Sie die Registerkarte **Queries** aus.
+ Fügen Sie die folgende Mutation in den Bereich **Queries (Abfragen)** ein. Außerdem müssen Sie das `id`-Argument mit dem zuvor notierten Wert aktualisieren.

  ```
  mutation votePost {
    upvotePost(id:123) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).
+ Der Beitrag wurde in DynamoDB aktualisiert und sollte im Ergebnisbereich rechts neben dem Abfragebereich angezeigt werden. Das sollte bei Ihnen ähnlich wie im folgenden Bild aussehen:

  ```
  {
    "data": {
      "upvotePost": {
        "id": "123",
        "author": "A new author",
        "title": "An empty story",
        "content": null,
        "url": "https://aws.amazon.com/appsync/",
        "ups": 6,
        "downs": 0,
        "version": 4
      }
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** einige weitere Male. Jedes Mal, wenn Sie die Abfrage ausführen, sollten die Felder `ups` und `version` um 1 erhöht werden.
+ Ändern Sie folgendermaßen die Abfrage zum Aufrufen der `downvotePost`-Mutation:

  ```
  mutation votePost {
    downvotePost(id:123) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche). Jedes Mal, wenn Sie die Abfrage ausführen, sollten jetzt die Felder `downs` und `version` um 1 erhöht werden.

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

## Den DeletePost-Resolver einrichten (DynamoDB) DeleteItem
<a name="setting-up-the-deletepost-resolver-ddb-deletepost"></a>

Mit der nächsten Mutation, die Sie einrichten möchten, soll ein Post gelöscht werden. Dazu verwenden Sie die `DeleteItem` DynamoDB-Operation.
+ Wählen Sie die Registerkarte **Schema** aus.
+ Ändern Sie im **Schemabereich** den `Mutation` Typ, um eine neue `deletePost` Mutation hinzuzufügen, wie folgt:

  ```
  type Mutation {
      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!
  }
  ```

  Dieses Mal wurde das Feld `expectedVersion` als optional konfiguriert. Dies wird später erläutert, wenn Sie die Anforderungszuweisungsvorlage hinzufügen.
+ Wählen Sie **Speichern**.
+ Suchen Sie rechts im Bereich **Data types (Datentypen)** das neue Feld **delete** des Typs **Mutation** und wählen Sie dann **Attach (Anhängen)**.
+ Wählen Sie im **Menü Aktion** die Option **Laufzeit aktualisieren** und anschließend **Unit Resolver (nur VTL**) aus.
+ Wählen Sie für **Data source name (Datenquellenname)** die Option **PostDynamoDBTable** aus.
+ Fügen Sie unter **Configure the request mapping template (Zuweisungsvorlage für Anforderungen konfigurieren)** Folgendes ein:

  ```
  {
      "version" : "2017-02-28",
      "operation" : "DeleteItem",
      "key": {
          "id": $util.dynamodb.toDynamoDBJson($context.arguments.id)
      }
      #if( $context.arguments.containsKey("expectedVersion") )
          ,"condition" : {
              "expression"       : "attribute_not_exists(id) OR version = :expectedVersion",
              "expressionValues" : {
                  ":expectedVersion" : $util.dynamodb.toDynamoDBJson($context.arguments.expectedVersion)
              }
          }
      #end
  }
  ```

   **Hinweis:** Das Argument `expectedVersion` ist ein optionales Argument. Wenn der Aufrufer ein `expectedVersion` Argument in der Anfrage festlegt, fügt die Vorlage eine Bedingung hinzu, die nur dann den Erfolg der `DeleteItem` Anfrage ermöglicht, wenn das Element bereits gelöscht wurde oder wenn das `version` Attribut des Beitrags in DynamoDB genau dem entspricht. `expectedVersion` Wenn es ausgelassen wird, wird kein Bedingungsausdruck für die `DeleteItem`-Anforderung angegeben. Es ist erfolgreich`version`, unabhängig vom Wert von oder ob das Element in DynamoDB vorhanden ist oder nicht.
+ Fügen Sie unter **Configure the response mapping template (Zuweisungsvorlage für Antworten konfigurieren)** Folgendes ein:

  ```
  $utils.toJson($context.result)
  ```

   **Hinweis:** Auch wenn Sie ein Element löschen, können Sie das gelöschte Element zurückgeben, sofern es nicht bereits vorher gelöscht wurde.
+ Wählen Sie **Speichern**.

Weitere Informationen zur `DeleteItem` Anforderungszuordnung finden Sie in der [DeleteItem](aws-appsync-resolver-mapping-template-reference-dynamodb-deleteitem.md)Referenzdokumentation.

### Aufrufen der API zum Löschen eines Posts
<a name="call-the-api-to-delete-a-post"></a>

Jetzt ist der Resolver eingerichtet und AWS AppSync weiß, wie man eine eingehende `delete` Mutation in eine `DeleteItem` DynamoDB-Operation übersetzt. Sie können jetzt eine Mutation ausführen, um Inhalte in der Tabelle zu löschen.
+ Wählen Sie die Registerkarte **Queries** aus.
+ Fügen Sie die folgende Mutation in den Bereich **Queries (Abfragen)** ein. Außerdem müssen Sie das `id`-Argument mit dem zuvor notierten Wert aktualisieren.

  ```
  mutation deletePost {
    deletePost(id:123) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).
+ Der Beitrag wurde aus DynamoDB gelöscht. Beachten Sie, dass der Wert des Elements AWS AppSync zurückgegeben wird, das aus DynamoDB gelöscht wurde und der im Ergebnisbereich rechts neben dem Abfragebereich angezeigt werden sollte. Das sollte bei Ihnen ähnlich wie im folgenden Bild aussehen:

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

Der Wert wird nur zurückgegeben, wenn dieser Aufruf von `deletePost` derjenige war, der ihn tatsächlich aus DynamoDB gelöscht hat.
+ Wählen Sie erneut **Execute query (Abfrage ausführen)**.
+ Der Aufruf ist weiterhin erfolgreich, es wird jedoch kein Wert zurückgegeben.

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

Löschen wir jetzt einen Post. Dieses Mal geben wir aber einen `expectedValue` an. Zuerst müssen Sie jedoch einen neuen Post erstellen, da der Post, mit dem Sie bisher gearbeitet haben, gerade gelöscht wurde.
+ Fügen Sie die folgende Mutation in den Bereich **Queries (Abfragen)** ein:

  ```
  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
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).
+ Die Ergebnisse des neu erstellten Posts sollten im Ergebnisbereich rechts neben dem Abfragebereich angezeigt werden. Notieren Sie die `id` des neu erstellten Objekts, da diese gleich benötigt wird. Das sollte bei Ihnen ähnlich wie im folgenden Bild aussehen:

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

Jetzt versuchen wir, diesen Post zu löschen, geben aber einen falschen Wert für `expectedVersion` an:
+ Fügen Sie die folgende Mutation in den Bereich **Queries (Abfragen)** ein. Außerdem müssen Sie das `id`-Argument mit dem zuvor notierten Wert aktualisieren.

  ```
  mutation deletePost {
    deletePost(
      id:123
      expectedVersion: 9999
    ) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).

  ```
  {
    "data": {
      "deletePost": null
    },
    "errors": [
      {
        "path": [
          "deletePost"
        ],
        "data": {
          "id": "123",
          "author": "AUTHORNAME",
          "title": "Our second post!",
          "content": "A new post.",
          "url": "https://aws.amazon.com/appsync/",
          "ups": 1,
          "downs": 0,
          "version": 1
        },
        "errorType": "DynamoDB:ConditionalCheckFailedException",
        "locations": [
          {
            "line": 2,
            "column": 3
          }
        ],
        "message": "The conditional request failed (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ConditionalCheckFailedException; Request ID: ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ)"
      }
    ]
  }
  ```

  Die Anforderung ist fehlgeschlagen, weil der Bedingungsausdruck als falsch ausgewertet wird: Der Wert für `version` des Beitrags in DynamoDB entspricht nicht dem in den Argumenten `expectedValue` angegebenen Wert. Der aktuelle Wert des Objekts wird im Feld `data` im Abschnitt `errors` der GraphQL-Antwort zurückgegeben.
+ Wiederholen Sie die Anforderung und korrigieren Sie dabei `expectedVersion`:

  ```
  mutation deletePost {
    deletePost(
      id:123
      expectedVersion: 1
    ) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).
+ Diesmal ist die Anfrage erfolgreich und der Wert, der aus DynamoDB gelöscht wurde, wird zurückgegeben:

  ```
  {
    "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
      }
    }
  }
  ```
+ Wählen Sie erneut **Execute query (Abfrage ausführen)**.
+ Der Aufruf ist immer noch erfolgreich, aber diesmal wird kein Wert zurückgegeben, da der Beitrag bereits in DynamoDB gelöscht wurde.

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

## Einrichten des allPost-Resolvers (DynamoDB Scan)
<a name="setting-up-the-allpost-resolver-dynamodb-scan"></a>

Bisher ist die API nur nützlich, wenn Sie die `id` eines jeden Beitrags kennen, den Sie betrachten möchten. Fügen wir jetzt einen neuen Resolver hinzu, der alle Posts in der Tabelle zurückgibt.
+ Wählen Sie die Registerkarte **Schema** aus.
+ Ändern Sie im **Schemabereich** den `Query` Typ, um eine neue `allPost` Abfrage hinzuzufügen, wie folgt:

  ```
  type Query {
      allPost(count: Int, nextToken: String): PaginatedPosts!
      getPost(id: ID): Post
  }
  ```
+ Fügen Sie einen neuen `PaginationPosts`-Typ hinzu:

  ```
  type PaginatedPosts {
      posts: [Post!]!
      nextToken: String
  }
  ```
+ Wählen Sie **Speichern**.
+ Suchen Sie rechts im Bereich **Data types (Datentypen)** das neue Feld **allPost** des Typs **Query (Abfrage)** und wählen Sie dann **Attach (Anhängen)**.
+ Wählen Sie im **Menü Aktion** die Option **Laufzeit aktualisieren** und anschließend **Unit Resolver (nur VTL**) aus.
+ Wählen Sie für **Data source name (Datenquellenname)** die Option **PostDynamoDBTable** aus.
+ Fügen Sie unter **Configure the request mapping template (Zuweisungsvorlage für Anforderungen konfigurieren)** Folgendes ein:

  ```
  {
      "version" : "2017-02-28",
      "operation" : "Scan"
      #if( ${context.arguments.count} )
          ,"limit": $util.toJson($context.arguments.count)
      #end
      #if( ${context.arguments.nextToken} )
          ,"nextToken": $util.toJson($context.arguments.nextToken)
      #end
  }
  ```

  Dieser Resolver verfügt über zwei optionale Argumente: `count` gibt die maximale Anzahl von Elementen an, die in einem Aufruf zurückgegeben werden sollen, und mit `nextToken` kann der nächste Ergebnissatz abgerufen werden. (Später wird erläutert, woher der Wert für `nextToken` stammt.)
+ Fügen Sie unter **Configure the response mapping template (Zuweisungsvorlage für Antworten konfigurieren)** Folgendes ein:

  ```
  {
      "posts": $utils.toJson($context.result.items)
      #if( ${context.result.nextToken} )
          ,"nextToken": $util.toJson($context.result.nextToken)
      #end
  }
  ```

   **Hinweis:** Diese Zuweisungsvorlage für Antworten unterscheidet sich von allen bisher betrachteten Zuweisungsvorlagen. Das Ergebnis der `allPost`-Abfrage ist `PaginatedPosts` mit einer Liste von Posts und einem Paginierungs-Token. Die Form dieses Objekts unterscheidet sich von dem, was vom AWS AppSync DynamoDB-Resolver zurückgegeben wird: Die Liste der Beiträge wird `items` in den AWS AppSync DynamoDB-Resolver-Ergebnissen aufgerufen, aber sie wird aufgerufen. `posts` `PaginatedPosts`
+ Wählen Sie **Speichern**.

[Weitere Informationen zur Zuordnung von `Scan` Anfragen finden Sie in der Referenzdokumentation zum Scannen.](aws-appsync-resolver-mapping-template-reference-dynamodb-scan.md)

### Aufrufen der API zum Scannen aller Posts
<a name="call-the-api-to-scan-all-posts"></a>

Jetzt ist der Resolver eingerichtet und AWS AppSync weiß, wie man eine eingehende `allPost` Abfrage in eine `Scan` DynamoDB-Operation übersetzt. Sie können jetzt die Tabelle scannen, um alle Posts abzurufen.

Bevor Sie dies ausprobieren können, muss allerdings die Tabelle mit Daten gefüllt werden, da Sie alle Daten gelöscht haben, mit denen Sie bislang gearbeitet haben.
+ Wählen Sie die Registerkarte **Queries** aus.
+ Fügen Sie die folgende Mutation in den Bereich **Queries (Abfragen)** ein:

  ```
  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 }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).

Scannen wir jetzt die Tabelle so, dass jeweils fünf Ergebnisse zurückgegeben werden.
+ Fügen Sie im Bereich **Queries (Abfragen)** die folgende Abfrage ein:

  ```
  query allPost {
    allPost(count: 5) {
      posts {
        id
        title
      }
      nextToken
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).
+ Die ersten fünf Posts sollten im Ergebnisbereich rechts neben dem Abfragebereich angezeigt werden. Das sollte bei Ihnen ähnlich wie im folgenden Bild aussehen:

  ```
  {
    "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": "eyJ2ZXJzaW9uIjoxLCJ0b2tlbiI6IkFRSUNBSGo4eHR0RG0xWXhUa1F0cEhXMEp1R3B0M1B3eThOSmRvcG9ad2RHYjI3Z0lnRkJEdXdUK09hcnovRGhNTGxLTGdMUEFBQUI1akNDQWVJR0NTcUdTSWIzRFFFSEJxQ0NBZE13Z2dIUEFnRUFNSUlCeUFZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF6ajFodkhKU1paT1pncTRaUUNBUkNBZ2dHWnJiR1dQWGxkMDB1N0xEdGY4Z2JsbktzRjRua1VCcks3TFJLcjZBTFRMeGFwVGJZMDRqOTdKVFQyYVRwSzdzbVdtNlhWWFVCTnFIOThZTzBWZHVkdDI2RlkxMHRqMDJ2QTlyNWJTUWpTbWh6NE5UclhUMG9KZWJSQ2JJbXBlaDRSVlg0Tis0WTVCN1IwNmJQWWQzOVhsbTlUTjBkZkFYMVErVCthaXZoNE5jMk50RitxVmU3SlJ5WmpzMEFkSGduM3FWd2VrOW5oeFVVd3JlK1loUks5QkRzemdiMDlmZmFPVXpzaFZ4cVJRbC93RURlOTcrRmVJdXZNby9NZ1F6dUdNbFRyalpNR3FuYzZBRnhwa0VlZTFtR0FwVDFISElUZlluakptYklmMGUzUmcxbVlnVHVSbDh4S0trNmR0QVoraEhLVDhuNUI3VnF4bHRtSnlNUXBrZGl6KzkyL3VzNDl4OWhrMnVxSW01ZFFwMjRLNnF0dm9ZK1BpdERuQTc5djhzb0grVytYT3VuQ2NVVDY4TVZ1Wk5KYkRuSEFSSEVlaTlVNVBTelU5RGZ6d2pPdmhqWDNJMWhwdWUrWi83MDVHVjlPQUxSTGlwZWZPeTFOZFhwZTdHRDZnQW00bUJUK2c1eC9Ec3ZDbWVnSDFDVXRTdHVuU1ZFa2JpZytQRC9oMUwyRTNqSHhVQldaa28yU256WUc0cG0vV1RSWkFVZHZuQT09In0="
      }
    }
  }
  ```

Sie haben fünf Ergebnisse und ein `nextToken`, das zum Abrufen des nächsten Ergebnissatzes verwendet werden kann.
+ Aktualisieren Sie die `allPost`-Abfrage, um das `nextToken` aus dem vorherigen Ergebnissatz einzuschließen:

  ```
  query allPost {
    allPost(
      count: 5
      nextToken: "eyJ2ZXJzaW9uIjoxLCJ0b2tlbiI6IkFRSUNBSGo4eHR0RG0xWXhUa1F0cEhXMEp1R3B0M1B3eThOSmRvcG9ad2RHYjI3Z0lnRlluNktJRWl6V0ZlR3hJOVJkaStrZUFBQUI1akNDQWVJR0NTcUdTSWIzRFFFSEJxQ0NBZE13Z2dIUEFnRUFNSUlCeUFZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF5cW8yUGFSZThnalFpemRCTUNBUkNBZ2dHWk1JODhUNzhIOFVUZGtpdFM2ZFluSWRyVDg4c2lkN1RjZzB2d1k3VGJTTWpSQ2U3WjY3TkUvU2I1dWNETUdDMmdmMHErSGJSL0pteGRzYzVEYnE1K3BmWEtBdU5jSENJdWNIUkJ0UHBPWVdWdCtsS2U5L1pNcWdocXhrem1RaXI1YnIvQkt6dU5hZmJCdE93NmtoM2Jna1BKM0RjWWhpMFBGbmhMVGg4TUVGSjBCcXg3RTlHR1V5N0tUS0JLZlV3RjFQZ0JRREdrNzFYQnFMK2R1S2IrVGtZZzVYMjFrc3NyQmFVTmNXZmhTeXE0ZUJHSWhqZWQ5c3VKWjBSSTc2ZnVQdlZkR3FLNENjQmxHYXhpekZnK2pKK1FneEU1SXduRTNYYU5TR0I4QUpmamR2bU1wbUk1SEdvWjlMUUswclczbG14RDRtMlBsaTNLaEVlcm9pem5zcmdINFpvcXIrN2ltRDN3QkJNd3BLbGQzNjV5Nnc4ZnMrK2FnbTFVOUlKOFFrOGd2bEgySHFROHZrZXBrMWlLdWRIQ25LaS9USnBlMk9JeEVPazVnRFlzRTRUU09HUlVJTkxYY2MvdW1WVEpBMUthV2hWTlAvdjNlSnlZQUszbWV6N2h5WHVXZ1BkTVBNWERQdTdjVnVRa3EwK3NhbGZOd2wvSUx4bHNyNDVwTEhuVFpyRWZvVlV1bXZ5S2VKY1RUU1lET05hM1NwWEd2UT09In0="
    ) {
      posts {
        id
        author
      }
      nextToken
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).
+ Die verbleibenden vier Posts sollten im Ergebnisbereich rechts neben dem Abfragebereich angezeigt werden. Dieser Ergebnissatz enthält kein `nextToken`, weil Sie alle neun Posts durchlaufen haben und keine mehr übrig sind. Das sollte bei Ihnen ähnlich wie im folgenden Bild aussehen:

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

## Den allPostsBy Author Resolver einrichten (DynamoDB Query)
<a name="setting-up-the-allpostsbyauthor-resolver-ddb-query"></a>

Sie können DynamoDB nicht nur nach allen Beiträgen durchsuchen, sondern auch DynamoDB abfragen, um Beiträge abzurufen, die von einem bestimmten Autor erstellt wurden. Die DynamoDB-Tabelle, die Sie zuvor erstellt haben, hat bereits einen `GlobalSecondaryIndex` Aufruf, den `author-index` Sie mit einer `Query` DynamoDB-Operation verwenden können, um alle Beiträge abzurufen, die von einem bestimmten Autor erstellt wurden.
+ Wählen Sie die Registerkarte **Schema** aus.
+ Ändern Sie im **Schemabereich** den `Query` Typ, um eine neue `allPostsByAuthor` Abfrage hinzuzufügen, wie folgt:

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

   **Hinweis:** Hier wird der gleiche `PaginatedPosts`-Typ wie in der `allPost`-Abfrage verwendet.
+ Wählen Sie **Speichern**.
+ Suchen Sie im Bereich **Datentypen** auf der rechten Seite nach dem neu erstellten **allPostsByAutorenfeld** für den **Abfragetyp**, und wählen Sie dann **Anhängen** aus.
+ Wählen Sie im **Menü Aktion** die Option **Laufzeit aktualisieren** und anschließend **Unit Resolver (nur VTL**) aus.
+ Wählen Sie für **Data source name (Datenquellenname)** die Option **PostDynamoDBTable** aus.
+ Fügen Sie unter **Configure the request mapping template (Zuweisungsvorlage für Anforderungen konfigurieren)** Folgendes ein:

  ```
  {
      "version" : "2017-02-28",
      "operation" : "Query",
      "index" : "author-index",
      "query" : {
        "expression": "author = :author",
          "expressionValues" : {
            ":author" : $util.dynamodb.toDynamoDBJson($context.arguments.author)
          }
      }
      #if( ${context.arguments.count} )
          ,"limit": $util.toJson($context.arguments.count)
      #end
      #if( ${context.arguments.nextToken} )
          ,"nextToken": "${context.arguments.nextToken}"
      #end
  }
  ```

  Dieser Resolver verfügt wie der `allPost`-Resolver über zwei optionale Argumente: `count` gibt die maximale Anzahl von Elementen an, die in einem Aufruf zurückgegeben werden sollen, und mit `nextToken` kann der nächste Ergebnissatz abgerufen werden. (Der Wert für `nextToken` kann aus einem vorherigen Abruf übernommen werden.)
+ Fügen Sie unter **Configure the response mapping template (Zuweisungsvorlage für Antworten konfigurieren)** Folgendes ein:

  ```
  {
      "posts": $utils.toJson($context.result.items)
      #if( ${context.result.nextToken} )
          ,"nextToken": $util.toJson($context.result.nextToken)
      #end
  }
  ```

   **Hinweis:** Dies ist die gleiche Zuweisungsvorlage für Antworten, die auch im `allPost`-Resolver verwendet wurde.
+ Wählen Sie **Speichern**.

Weitere Informationen zur `Query` Anforderungszuordnung finden Sie in der [Query-Referenzdokumentation](aws-appsync-resolver-mapping-template-reference-dynamodb-query.md).

### Aufrufen der API zum Abfragen aller Posts von einem Autor
<a name="call-the-api-to-query-all-posts-by-an-author"></a>

Jetzt ist der Resolver eingerichtet und AWS AppSync weiß, wie man eine eingehende `allPostsByAuthor` Mutation in eine `Query` DynamoDB-Operation gegen den Index übersetzt. `author-index` Sie können nun die Tabelle abfragen, um alle Posts von einem bestimmten Autor abzurufen.

Zuvor müssen Sie jedoch die Tabelle mit weiteren Post-Daten füllen, da bisher alle Posts den gleichen Autor haben.
+ Wählen Sie die Registerkarte **Queries** aus.
+ Fügen Sie die folgende Mutation in den Bereich **Queries (Abfragen)** ein:

  ```
  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 }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).

Wir fragen jetzt die Tabelle ab, so dass alle Posts von `Nadia` zurückgegeben werden.
+ Fügen Sie im Bereich **Queries (Abfragen)** die folgende Abfrage ein:

  ```
  query allPostsByAuthor {
    allPostsByAuthor(author: "Nadia") {
      posts {
        id
        title
      }
      nextToken
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).
+ Alle Posts von `Nadia` sollten im Ergebnisbereich rechts neben dem Abfragebereich angezeigt werden. Das sollte bei Ihnen ähnlich wie im folgenden Bild aussehen:

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

Die Paginierung funktioniert für `Query` genauso wie für `Scan`. Suchen wir z. B. nach allen Posts von `AUTHORNAME`, wobei jeweils fünf Posts abgerufen werden.
+ Fügen Sie im Bereich **Queries (Abfragen)** die folgende Abfrage ein:

  ```
  query allPostsByAuthor {
    allPostsByAuthor(
      author: "AUTHORNAME"
      count: 5
    ) {
      posts {
        id
        title
      }
      nextToken
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).
+ Alle Posts von `AUTHORNAME` sollten im Ergebnisbereich rechts neben dem Abfragebereich angezeigt werden. Das sollte bei Ihnen ähnlich wie im folgenden Bild aussehen:

  ```
  {
    "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": "eyJ2ZXJzaW9uIjoxLCJ0b2tlbiI6IkFRSUNBSGo4eHR0RG0xWXhUa1F0cEhXMEp1R3B0M1B3eThOSmRvcG9ad2RHYjI3Z0lnSExqRnVhVUR3ZUhEZ2QzNGJ2QlFuY0FBQUNqekNDQW9zR0NTcUdTSWIzRFFFSEJxQ0NBbnd3Z2dKNEFnRUFNSUlDY1FZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF5Qkg4Yk1obW9LVEFTZHM3SUNBUkNBZ2dKQ3dISzZKNlJuN3pyYUVKY1pWNWxhSkNtZW1KZ0F5N1dhZkc2UEdTNHpNQzJycTkwZHFJTFV6Z25wck9Gd3pMS3VOQ2JvUXc3VDI5eCtnVExIbGg4S3BqbzB1YjZHQ3FwcDhvNDVmMG9JbDlmdS9JdjNXcFNNSXFKTXZ1MEVGVWs1VzJQaW5jZGlUaVRtZFdYWlU1bkV2NkgyRFBRQWZYYlNnSmlHSHFLbmJZTUZZM0FTdmRIL0hQaVZBb1RCMk1YZkg0eGJOVTdEbjZtRFNhb2QwbzdHZHJEWDNtODQ1UXBQUVNyUFhHemY0WDkyajhIdlBCSWE4Smcrb0RxbHozUVQ5N2FXUXdYWWU2S0h4emI1ejRITXdEdXEyRDRkYzhoMi9CbW10MzRMelVGUVIyaExSZGRaZ0xkdzF5cHJZdFZwY3dEc1d4UURBTzdOcjV2ZEp4VVR2TVhmODBRSnp1REhXREpTVlJLdDJwWmlpaXhXeGRwRmNod1BzQ3d2aVBqMGwrcWFFWU1jMXNQbENkVkFGem43VXJrSThWbS8wWHlwR2xZb3BSL2FkV0xVekgrbGMrYno1ZEM2SnVLVXdtY1EyRXlZeDZiS0Izbi9YdUViWGdFeU5PMWZTdE1rRlhyWmpvMVpzdlYyUFRjMzMrdEs0ZDhkNkZrdjh5VVR6WHhJRkxIaVNsOUx6VVdtT3BCaWhrTFBCT09jcXkyOHh1UmkzOEM3UFRqMmN6c3RkOUo1VUY0azBJdUdEbVZzM2xjdWg1SEJjYThIeXM2aEpvOG1HbFpMNWN6R2s5bi8vRE1EbDY3RlJraG5QNFNhSDBpZGI5VFEvMERLeFRBTUdhcWpPaEl5ekVqd2ZDQVJleFdlbldyOGlPVkhScDhGM25WZVdvbFRGK002N0xpdi9XNGJXdDk0VEg3b0laUU5lYmZYKzVOKy9Td25Hb1dyMTlWK0pEb2lIRVFLZ1cwMWVuYjZKUXo5Slh2Tm95ZzF3RnJPVmxGc2xwNlRHa1BlN2Rnd2IrWT0ifQ=="
      }
    }
  }
  ```
+ Aktualisieren Sie das `nextToken`-Argument mit dem Wert, der in der vorherigen Abfrage zurückgegeben wurde:

  ```
  query allPostsByAuthor {
    allPostsByAuthor(
      author: "AUTHORNAME"
      count: 5
      nextToken: "eyJ2ZXJzaW9uIjoxLCJ0b2tlbiI6IkFRSUNBSGo4eHR0RG0xWXhUa1F0cEhXMEp1R3B0M1B3eThOSmRvcG9ad2RHYjI3Z0lnSExqRnVhVUR3ZUhEZ2QzNGJ2QlFuY0FBQUNqekNDQW9zR0NTcUdTSWIzRFFFSEJxQ0NBbnd3Z2dKNEFnRUFNSUlDY1FZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF5Qkg4Yk1obW9LVEFTZHM3SUNBUkNBZ2dKQ3dISzZKNlJuN3pyYUVKY1pWNWxhSkNtZW1KZ0F5N1dhZkc2UEdTNHpNQzJycTkwZHFJTFV6Z25wck9Gd3pMS3VOQ2JvUXc3VDI5eCtnVExIbGg4S3BqbzB1YjZHQ3FwcDhvNDVmMG9JbDlmdS9JdjNXcFNNSXFKTXZ1MEVGVWs1VzJQaW5jZGlUaVRtZFdYWlU1bkV2NkgyRFBRQWZYYlNnSmlHSHFLbmJZTUZZM0FTdmRIL0hQaVZBb1RCMk1YZkg0eGJOVTdEbjZtRFNhb2QwbzdHZHJEWDNtODQ1UXBQUVNyUFhHemY0WDkyajhIdlBCSWE4Smcrb0RxbHozUVQ5N2FXUXdYWWU2S0h4emI1ejRITXdEdXEyRDRkYzhoMi9CbW10MzRMelVGUVIyaExSZGRaZ0xkdzF5cHJZdFZwY3dEc1d4UURBTzdOcjV2ZEp4VVR2TVhmODBRSnp1REhXREpTVlJLdDJwWmlpaXhXeGRwRmNod1BzQ3d2aVBqMGwrcWFFWU1jMXNQbENkVkFGem43VXJrSThWbS8wWHlwR2xZb3BSL2FkV0xVekgrbGMrYno1ZEM2SnVLVXdtY1EyRXlZeDZiS0Izbi9YdUViWGdFeU5PMWZTdE1rRlhyWmpvMVpzdlYyUFRjMzMrdEs0ZDhkNkZrdjh5VVR6WHhJRkxIaVNsOUx6VVdtT3BCaWhrTFBCT09jcXkyOHh1UmkzOEM3UFRqMmN6c3RkOUo1VUY0azBJdUdEbVZzM2xjdWg1SEJjYThIeXM2aEpvOG1HbFpMNWN6R2s5bi8vRE1EbDY3RlJraG5QNFNhSDBpZGI5VFEvMERLeFRBTUdhcWpPaEl5ekVqd2ZDQVJleFdlbldyOGlPVkhScDhGM25WZVdvbFRGK002N0xpdi9XNGJXdDk0VEg3b0laUU5lYmZYKzVOKy9Td25Hb1dyMTlWK0pEb2lIRVFLZ1cwMWVuYjZKUXo5Slh2Tm95ZzF3RnJPVmxGc2xwNlRHa1BlN2Rnd2IrWT0ifQ=="
    ) {
      posts {
        id
        title
      }
      nextToken
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).
+ Alle verbleibenden Posts von `AUTHORNAME` sollten im Ergebnisbereich rechts neben dem Abfragebereich angezeigt werden. Das sollte bei Ihnen ähnlich wie im folgenden Bild aussehen:

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

## Verwenden von Sätzen
<a name="using-sets"></a>

Bis zu diesem Zeitpunkt war der `Post` Typ ein flaches Objekt. key/value Sie können mit dem AWS AppSyncDynamo DB-Resolver auch komplexe Objekte wie Gruppen, Listen und Maps modellieren.

Aktualisieren wir jetzt den `Post`-Typ, so dass er Tags enthält. Ein Beitrag kann 0 oder mehr Tags haben, die in DynamoDB als String-Set gespeichert werden. Außerdem richten Sie einige Mutationen ein, um Tags hinzuzufügen und zu entfernen, sowie eine neue Abfrage zum Scannen nach Posts mit einem bestimmten Tag.
+ Wählen Sie die Registerkarte **Schema** aus.
+ Ändern Sie im **Schemabereich** den `Post` Typ wie folgt, um ein neues `tags` Feld hinzuzufügen:

  ```
  type Post {
    id: ID!
    author: String
    title: String
    content: String
    url: String
    ups: Int!
    downs: Int!
    version: Int!
    tags: [String!]
  }
  ```
+ Ändern Sie im **Schemabereich** den `Query` Typ, um eine neue `allPostsByTag` Abfrage hinzuzufügen, wie folgt:

  ```
  type Query {
    allPostsByTag(tag: String!, count: Int, nextToken: String): PaginatedPosts!
    allPostsByAuthor(author: String!, count: Int, nextToken: String): PaginatedPosts!
    allPost(count: Int, nextToken: String): PaginatedPosts!
    getPost(id: ID): Post
  }
  ```
+ Ändern Sie im **Schemabereich** den `Mutation` Typ, um neue `addTag` und `removeTag` Mutationen hinzuzufügen, wie folgt:

  ```
  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!
  }
  ```
+ Wählen Sie **Speichern**.
+ Suchen Sie im Bereich **Datentypen** auf der rechten Seite nach dem neu erstellten **allPostsByTag-Feld** für den **Abfragetyp**, und wählen Sie dann **Anhängen** aus.
+ Wählen Sie für **Data source name (Datenquellenname)** die Option **PostDynamoDBTable** aus.
+ Fügen Sie unter **Configure the request mapping template (Zuweisungsvorlage für Anforderungen konfigurieren)** Folgendes ein:

  ```
  {
      "version" : "2017-02-28",
      "operation" : "Scan",
      "filter": {
        "expression": "contains (tags, :tag)",
          "expressionValues": {
            ":tag": $util.dynamodb.toDynamoDBJson($context.arguments.tag)
          }
      }
      #if( ${context.arguments.count} )
          ,"limit": $util.toJson($context.arguments.count)
      #end
      #if( ${context.arguments.nextToken} )
          ,"nextToken": $util.toJson($context.arguments.nextToken)
      #end
  }
  ```
+ Fügen Sie unter **Configure the response mapping template (Zuweisungsvorlage für Antworten konfigurieren)** Folgendes ein:

  ```
  {
      "posts": $utils.toJson($context.result.items)
      #if( ${context.result.nextToken} )
          ,"nextToken": $util.toJson($context.result.nextToken)
      #end
  }
  ```
+ Wählen Sie **Speichern**.
+ Suchen Sie rechts im Bereich **Data types (Datentypen)** das neue Feld **addTag** des Typs **Mutation** und wählen Sie dann **Attach (Anhängen)**.
+ Wählen Sie für **Data source name (Datenquellenname)** die Option **PostDynamoDBTable** aus.
+ Fügen Sie unter **Configure the request mapping template (Zuweisungsvorlage für Anforderungen konfigurieren)** Folgendes ein:

  ```
  {
      "version" : "2017-02-28",
      "operation" : "UpdateItem",
      "key" : {
          "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
      },
      "update" : {
          "expression" : "ADD tags :tags, version :plusOne",
          "expressionValues" : {
              ":tags" : { "SS": [ $util.toJson($context.arguments.tag) ] },
              ":plusOne" : { "N" : 1 }
          }
      }
  }
  ```
+ Fügen Sie unter **Configure the response mapping template (Zuweisungsvorlage für Antworten konfigurieren)** Folgendes ein:

  ```
  $utils.toJson($context.result)
  ```
+ Wählen Sie **Speichern**.
+ Suchen Sie rechts im Bereich **Data types (Datentypen)** das neue Feld **removeTag** des Typs **Mutation** und wählen Sie dann **Attach (Anhängen)**.
+ Wählen Sie für **Data source name (Datenquellenname)** die Option **PostDynamoDBTable** aus.
+ Fügen Sie unter **Configure the request mapping template (Zuweisungsvorlage für Anforderungen konfigurieren)** Folgendes ein:

  ```
  {
      "version" : "2017-02-28",
      "operation" : "UpdateItem",
      "key" : {
          "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
      },
      "update" : {
          "expression" : "DELETE tags :tags ADD version :plusOne",
          "expressionValues" : {
              ":tags" : { "SS": [ $util.toJson($context.arguments.tag) ] },
              ":plusOne" : { "N" : 1 }
          }
      }
  }
  ```
+ Fügen Sie unter **Configure the response mapping template (Zuweisungsvorlage für Antworten konfigurieren)** Folgendes ein:

  ```
  $utils.toJson($context.result)
  ```
+ Wählen Sie **Speichern**.

### Aufrufen der API zum Arbeiten mit Tags
<a name="call-the-api-to-work-with-tags"></a>

Jetzt, wo Sie die Resolver eingerichtet haben, AWS AppSync weiß er, wie eingehende `addTag` `allPostsByTag` Anfragen und Anfragen in DynamoDB `UpdateItem` und Operationen übersetzt werden. `removeTag` `Scan`

Wählen Sie zum Ausprobieren einen der zuvor erstellten Posts aus. Verwenden wir als Beispiel einen Post, der von `Nadia` verfasst wurde.
+ Wählen Sie die Registerkarte **Queries** aus.
+ Fügen Sie im Bereich **Queries (Abfragen)** die folgende Abfrage ein:

  ```
  query allPostsByAuthor {
    allPostsByAuthor(
      author: "Nadia"
    ) {
      posts {
        id
        title
      }
      nextToken
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).
+ Alle Posts von Nadia sollten im Ergebnisbereich rechts neben dem Abfragebereich angezeigt werden. Das sollte bei Ihnen ähnlich wie im folgenden Bild aussehen:

  ```
  {
    "data": {
      "allPostsByAuthor": {
        "posts": [
          {
            "id": "10",
            "title": "The cutest dog in the world"
          },
          {
            "id": "11",
            "title": "Did you known...?"
          }
        ],
        "nextToken": null
      }
    }
  }
  ```
+ Verwenden wir den Post mit dem Titel `"The cutest dog in the world"`. Notieren Sie dessen `id`, da diese später benötigt wird.

Fügen wir jetzt den Tag `dog` hinzu.
+ Fügen Sie die folgende Mutation in den Bereich **Queries (Abfragen)** ein. Außerdem müssen Sie das `id`-Argument mit dem zuvor notierten Wert aktualisieren.

  ```
  mutation addTag {
    addTag(id:10 tag: "dog") {
      id
      title
      tags
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).
+ Der Post wird mit dem neuen Tag aktualisiert.

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

Sie können weitere Tags folgendermaßen hinzufügen:
+ Aktualisieren Sie die Mutation und ändern Sie das `tag`-Argument in `puppy`.

  ```
  mutation addTag {
    addTag(id:10 tag: "puppy") {
      id
      title
      tags
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).
+ Der Post wird mit dem neuen Tag aktualisiert.

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

Tags können auch gelöscht werden:
+ Fügen Sie die folgende Mutation in den Bereich **Queries (Abfragen)** ein. Außerdem müssen Sie das `id`-Argument mit dem zuvor notierten Wert aktualisieren.

  ```
  mutation removeTag {
    removeTag(id:10 tag: "puppy") {
      id
      title
      tags
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).
+ Der Post wird aktualisiert und das Tag `puppy` wird gelöscht.

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

Sie können auch alle Posts mit einem Tag suchen:
+ Fügen Sie im Bereich **Queries (Abfragen)** die folgende Abfrage ein:

  ```
  query allPostsByTag {
    allPostsByTag(tag: "dog") {
      posts {
        id
        title
        tags
      }
      nextToken
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).
+ Alle Posts mit dem Tag `dog` werden folgendermaßen zurückgegeben:

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

## Verwenden von Listen und Zuordnungen
<a name="using-lists-and-maps"></a>

Neben DynamoDB-Sets können Sie auch DynamoDB-Listen und -Maps verwenden, um komplexe Daten in einem einzigen Objekt zu modellieren.

Fügen wir nun die Möglichkeit hinzu, Posts Kommentare hinzuzufügen. Dies wird als Liste von Kartenobjekten für das `Post` Objekt in DynamoDB modelliert.

 **Hinweis:** In einer realen Anwendung würden Sie Kommentare in der eigenen Tabelle modellieren. Für dieses Tutorial fügen Sie sie einfach in die `Post`-Tabelle ein.
+ Wählen Sie die Registerkarte **Schema** aus.
+ Fügen Sie im Bereich **Schema** folgendermaßen einen neuen `Comment`-Typ hinzu:

  ```
  type Comment {
      author: String!
      comment: String!
  }
  ```
+ Ändern Sie im **Schemabereich** den `Post` Typ wie folgt, um ein neues `comments` Feld hinzuzufügen:

  ```
  type Post {
    id: ID!
    author: String
    title: String
    content: String
    url: String
    ups: Int!
    downs: Int!
    version: Int!
    tags: [String!]
    comments: [Comment!]
  }
  ```
+ Ändern Sie im **Schemabereich** den `Mutation` Typ wie folgt, um eine neue `addComment` Mutation hinzuzufügen:

  ```
  type Mutation {
    addComment(id: ID!, author: String!, comment: String!): Post
    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!
  }
  ```
+ Wählen Sie **Speichern**.
+ Suchen Sie rechts im Bereich **Data types (Datentypen)** das neue Feld **addComment** des Typs **Mutation** und wählen Sie dann **Attach (Anhängen)**.
+ Wählen Sie für **Data source name (Datenquellenname)** die Option **PostDynamoDBTable** aus.
+ Fügen Sie unter **Configure the request mapping template (Zuweisungsvorlage für Anforderungen konfigurieren)** Folgendes ein:

  ```
  {
    "version" : "2017-02-28",
    "operation" : "UpdateItem",
    "key" : {
      "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
    },
    "update" : {
      "expression" : "SET comments = list_append(if_not_exists(comments, :emptyList), :newComment) ADD version :plusOne",
      "expressionValues" : {
        ":emptyList": { "L" : [] },
        ":newComment" : { "L" : [
          { "M": {
            "author": $util.dynamodb.toDynamoDBJson($context.arguments.author),
            "comment": $util.dynamodb.toDynamoDBJson($context.arguments.comment)
            }
          }
        ] },
        ":plusOne" : $util.dynamodb.toDynamoDBJson(1)
      }
    }
  }
  ```

  Dieser Aktualisierungsausdruck fügt eine Liste mit dem neuen Kommentar an die vorhandene `comments`-Liste an. Wenn die Liste noch nicht vorhanden ist, wird sie erstellt.
+ Fügen Sie unter **Configure the response mapping template (Zuweisungsvorlage für Antworten konfigurieren)** Folgendes ein:

  ```
  $utils.toJson($context.result)
  ```
+ Wählen Sie **Speichern**.

### Aufrufen der API zum Hinzufügen eines Kommentars
<a name="call-the-api-to-add-a-comment"></a>

Jetzt, wo Sie die Resolver eingerichtet haben, AWS AppSync weiß, wie eingehende `addComment` Anfragen in `UpdateItem` DynamoDB-Operationen übersetzt werden.

Fügen Sie zum Ausprobieren einen Kommentar zu dem Post hinzu, dem auch die Tags hinzugefügt wurden.
+ Wählen Sie die Registerkarte **Queries** aus.
+ Fügen Sie im Bereich **Queries (Abfragen)** die folgende Abfrage ein:

  ```
  mutation addComment {
    addComment(
      id:10
      author: "Steve"
      comment: "Such a cute dog."
    ) {
      id
      comments {
        author
        comment
      }
    }
  }
  ```
+ Wählen Sie **Execute query (Abfrage ausführen)** (orangefarbene Wiedergabeschaltfläche).
+ Alle Posts von Nadia sollten im Ergebnisbereich rechts neben dem Abfragebereich angezeigt werden. Das sollte bei Ihnen ähnlich wie im folgenden Bild aussehen:

  ```
  {
    "data": {
      "addComment": {
        "id": "10",
        "comments": [
          {
            "author": "Steve",
            "comment": "Such a cute dog."
          }
        ]
      }
    }
  }
  ```

Wenn Sie die Anforderung mehrmals ausführen, werden mehrere Kommentare an die Liste angefügt.

## Schlussfolgerung
<a name="conclusion"></a>

In diesem Tutorial haben Sie eine API erstellt, mit der wir Post-Objekte in DynamoDB mithilfe AWS AppSync von GraphQL bearbeiten können. Weitere Informationen finden Sie unter [Referenz für Resolver-Zuweisungsvorlagen](resolver-mapping-template-reference.md#aws-appsync-resolver-mapping-template-reference).

Zum Aufräumen können Sie die AppSync GraphQL-API von der Konsole löschen.

Um die DynamoDB-Tabelle und die IAM-Rolle zu löschen, die Sie für dieses Tutorial erstellt haben, können Sie Folgendes ausführen, um den `AWSAppSyncTutorialForAmazonDynamoDB` Stack zu löschen, oder die CloudFormation Konsole aufrufen und den Stack löschen:

```
aws cloudformation delete-stack \
    --stack-name AWSAppSyncTutorialForAmazonDynamoDB
```

# Verwendung von AWS Lambda Resolvern in AWS AppSync
<a name="tutorial-lambda-resolvers"></a>

**Anmerkung**  
Wir unterstützen jetzt hauptsächlich die APPSYNC\$1JS-Laufzeit und ihre Dokumentation. [Bitte erwägen Sie, die APPSYNC\$1JS-Laufzeit und ihre Anleitungen hier zu verwenden.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

Sie können AWS Lambda with verwenden AWS AppSync , um jedes GraphQL-Feld aufzulösen. Beispielsweise könnte eine GraphQL-Abfrage einen Aufruf an eine Amazon Relational Database Service (Amazon RDS) -Instance senden, und eine GraphQL-Mutation könnte in einen Amazon Kinesis Kinesis-Stream schreiben. In diesem Abschnitt zeigen wir Ihnen, wie Sie eine Lambda-Funktion schreiben, die Geschäftslogik auf der Grundlage des Aufrufs einer GraphQL-Feldoperation ausführt.

## Erstellen einer Lambda-Funktion
<a name="create-a-lam-function"></a>

Das folgende Beispiel zeigt eine eingeschriebene Lambda-Funktion`Node.js`, die als Teil einer Blogpost-Anwendung verschiedene Operationen an Blogbeiträgen ausführt.

```
exports.handler = (event, context, callback) => {
    console.log("Received event {}", JSON.stringify(event, 3));
    var 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"} };

    var 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.");
    switch(event.field) {
        case "getPost":
            var id = event.arguments.id;
            callback(null, posts[id]);
            break;
        case "allPosts":
            var values = [];
            for(var d in posts){
                values.push(posts[d]);
            }
            callback(null, values);
            break;
        case "addPost":
            // return the arguments back
            callback(null, event.arguments);
            break;
        case "addPostErrorWithData":
            var id = event.arguments.id;
            var result = posts[id];
            // attached additional error information to the post
            result.errorMessage = 'Error with the mutation, data has changed';
            result.errorType = 'MUTATION_ERROR';
            callback(null, result);
            break;
        case "relatedPosts":
            var id = event.source.id;
            callback(null, relatedPosts[id]);
            break;
        default:
            callback("Unknown field, unable to resolve" + event.field, null);
            break;
    }
};
```

Diese Lambda-Funktion ruft einen Beitrag nach ID ab, fügt einen Beitrag hinzu, ruft eine Liste von Beiträgen ab und ruft verwandte Beiträge für einen bestimmten Beitrag ab.

 **Hinweis:** Die Lambda-Funktion verwendet die `switch` Anweisung on`event.field`, um zu ermitteln, welches Feld gerade aufgelöst wird.

Erstellen Sie diese Lambda-Funktion mit der AWS Management Console oder einem AWS CloudFormation Stack. Um die Funktion aus einem CloudFormation Stack zu erstellen, können Sie den folgenden Befehl AWS Command Line Interface (AWS CLI) verwenden:

```
aws cloudformation create-stack --stack-name AppSyncLambdaExample \
--template-url https://s3.us-west-2.amazonaws.com/awsappsync/resources/lambda/LambdaCFTemplate.yaml \
--capabilities CAPABILITY_NAMED_IAM
```

Sie können den CloudFormation Stack auch in der AWS Region USA West (Oregon) in Ihrem AWS Konto von hier aus starten:

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

## Eine Datenquelle für Lambda konfigurieren
<a name="configure-data-source-for-lamlong"></a>

Nachdem Sie die Lambda-Funktion erstellt haben, navigieren Sie in der AWS AppSync Konsole zu Ihrer GraphQL-API und wählen Sie dann die Registerkarte **Datenquellen**.

**Wählen Sie **Datenquelle erstellen**, geben Sie einen benutzerfreundlichen **Datenquellennamen** ein (z. B.**Lambda**), und wählen Sie AWS Lambda dann als **Datenquellentyp** die Option Funktion aus.** Wählen Sie für **Region** dieselbe Region wie Ihre Funktion aus. (Wenn Sie die Funktion aus dem bereitgestellten CloudFormation Stack erstellt haben, befindet sich die Funktion wahrscheinlich in **US-WEST-2**.) Wählen Sie für **Function ARN** den Amazon Resource Name (ARN) Ihrer Lambda-Funktion.

Nachdem Sie Ihre Lambda-Funktion ausgewählt haben, können Sie entweder eine neue AWS Identity and Access Management (IAM-) Rolle erstellen (für die die entsprechenden Berechtigungen AWS AppSync zugewiesen werden) oder eine vorhandene Rolle mit der folgenden Inline-Richtlinie auswählen:

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

****  

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

------

Sie müssen außerdem wie folgt eine Vertrauensbeziehung mit AWS AppSync der IAM-Rolle einrichten:

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

****  

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

------

## Erstellen Sie ein GraphQL-Schema
<a name="creating-a-graphql-schema"></a>

Nachdem die Datenquelle mit Ihrer Lambda-Funktion verbunden ist, erstellen Sie ein GraphQL-Schema.

Stellen Sie im Schema-Editor in der AWS AppSync Konsole sicher, dass Ihr Schema dem folgenden Schema entspricht:

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

## Resolver konfigurieren
<a name="configuring-resolvers"></a>

Nachdem Sie nun eine Lambda-Datenquelle und ein gültiges GraphQL-Schema registriert haben, können Sie Ihre GraphQL-Felder mithilfe von Resolvern mit Ihrer Lambda-Datenquelle verbinden.

Um einen Resolver zu erstellen, benötigen Sie Mapping-Vorlagen. Weitere Informationen zu Mapping-Vorlagen finden Sie unter[Resolver Mapping Template Overview](resolver-mapping-template-reference-overview.md#aws-appsync-resolver-mapping-template-reference-overview).

Weitere Informationen zu Lambda-Mapping-Vorlagen finden Sie unter[Resolver mapping template reference for Lambda](resolver-mapping-template-reference-lambda.md#aws-appsync-resolver-mapping-template-reference-lambda).

In diesem Schritt fügen Sie der Lambda-Funktion einen Resolver für die folgenden Felder hinzu:`getPost(id:ID!): Post`, `allPosts: [Post]``addPost(id: ID!, author: String!, title: String, content: String, url: String): Post!`, und. `Post.relatedPosts: [Post]`

Wählen Sie im Schema-Editor in der AWS AppSync Konsole auf der rechten Seite **Attach Resolver** for aus. `getPost(id:ID!): Post`

Wählen Sie dann im **Menü Aktion** die Option **Laufzeit aktualisieren** und anschließend **Unit Resolver (nur VTL**) aus.

Wählen Sie anschließend Ihre Lambda-Datenquelle aus. Wählen Sie im Bereich **request mapping template (Anforderungszuweisungsvorlage)** **Invoke And Forward Arguments (Argumente aufrufen und weiterleiten)**.

Ändern Sie das Objekt `payload`, um den Feldnamen hinzuzufügen. Ihre Vorlage sollte jetzt wie folgt aussehen:

```
{
    "version": "2017-02-28",
    "operation": "Invoke",
    "payload": {
        "field": "getPost",
        "arguments":  $utils.toJson($context.arguments)
    }
}
```

Wählen Sie im Bereich **response mapping template (Antwortzuweisungsvorlage)** **Return Lambda Result (Lambda-Ergebnis zurückgeben)** aus.

Verwenden Sie in diesem Fall die Basisvorlage in unveränderter Form. Sie sollte wie folgt aussehen:

```
$utils.toJson($context.result)
```

Wählen Sie **Speichern**. Sie haben nun den ersten Resolver angehängt. Wiederholen Sie diese Operation wie folgt für die verbleibenden Felder:

Für die `addPost(id: ID!, author: String!, title: String, content: String, url: String): Post!`-Anforderungszuweisungsvorlage:

```
{
    "version": "2017-02-28",
    "operation": "Invoke",
    "payload": {
        "field": "addPost",
        "arguments":  $utils.toJson($context.arguments)
    }
}
```

Für die `addPost(id: ID!, author: String!, title: String, content: String, url: String): Post!`-Antwortzuweisungsvorlage:

```
$utils.toJson($context.result)
```

Für die `allPosts: [Post]`-Anforderungszuweisungsvorlage:

```
{
    "version": "2017-02-28",
    "operation": "Invoke",
    "payload": {
        "field": "allPosts"
    }
}
```

Für die `allPosts: [Post]`-Antwortzuweisungsvorlage:

```
$utils.toJson($context.result)
```

Für die `Post.relatedPosts: [Post]`-Anforderungszuweisungsvorlage:

```
{
    "version": "2017-02-28",
    "operation": "Invoke",
    "payload": {
        "field": "relatedPosts",
        "source":  $utils.toJson($context.source)
    }
}
```

Für die `Post.relatedPosts: [Post]`-Antwortzuweisungsvorlage:

```
$utils.toJson($context.result)
```

## Testen Sie Ihre GraphQL-API
<a name="testing-your-graphql-api"></a>

Jetzt ist Ihre Lambda-Funktion mit GraphQL-Resolvern verbunden und Sie können einige Mutationen und Abfragen mithilfe der Konsole oder einer Client-Anwendung ausführen.

Wählen Sie auf der linken Seite der AWS AppSync Konsole **Abfragen** aus und fügen Sie dann den folgenden Code ein:

### addPost-Mutation
<a name="addpost-mutation"></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-Abfrage
<a name="getpost-query"></a>

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

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

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

## Zurückkehrende Fehler
<a name="returning-errors"></a>

Jede gegebene Feldauflösung kann zu einem Fehler führen. Mit AWS AppSync können Sie Fehler aus den folgenden Quellen melden:
+ Anforderungs- oder Antwortzuweisungsvorlage
+ Lambda-Funktion

### Von der Zuweisungsvorlage
<a name="from-the-mapping-template"></a>

Um absichtliche Fehler auszulösen, können Sie die `$utils.error` Hilfsmethode aus der Vorlage Velocity Template Language (VTL) verwenden. Das Argument enthält die `errorMessage`, den `errorType` und einen optionalen `data`-Wert. `data` ist hilfreich, um zusätzliche Daten an den Client zurückzugeben, wenn ein Fehler auftritt. Das Objekt `data` wird `errors` der endgültigen GraphQL-Antwort hinzugefügt.

Das folgende Beispiel zeigt, wie Sie es in der Antwortzuweisungsvorlage `Post.relatedPosts: [Post]` verwenden:

```
$utils.error("Failed to fetch relatedPosts", "LambdaFailure", $context.result)
```

Dies löst eine GraphQL-Antwort ähnlich der Folgenden aus:

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

Dabei ist `allPosts[0].relatedPosts` gleich *null*, weil ein Fehler aufgetreten ist und `errorMessage`, `errorType` und `data` im Objekt `data.errors[0]` vorhanden sind.

### Von der Lambda-Funktion
<a name="from-the-lam-function"></a>

AWS AppSync versteht auch Fehler, die die Lambda-Funktion auslöst. Mit dem Lambda-Programmiermodell können Sie *behandelte Fehler melden*. Wenn die Lambda-Funktion einen Fehler ausgibt, AWS AppSync kann das aktuelle Feld nicht aufgelöst werden. Nur die von Lambda zurückgegebene Fehlermeldung ist in der Antwort enthalten. Derzeit können Sie keine überflüssigen Daten an den Client zurückgeben, indem Sie einen Fehler in der Lambda-Funktion auslösen.

 **Hinweis**: Wenn Ihre Lambda-Funktion einen *unbehandelten* Fehler auslöst, AWS AppSync verwendet sie die von Lambda festgelegte Fehlermeldung.

Die folgenden Lambda-Funktion löst einen Fehler aus:

```
exports.handler = (event, context, callback) => {
    console.log("Received event {}", JSON.stringify(event, 3));
    callback("I fail. Always.");
};
```

Dadurch wird eine GraphQL-Antwort ähnlich der folgenden ausgegeben:

```
{
    "data": {
        "allPosts": [
            {
                "id": "2",
                "title": "Second book",
                "relatedPosts": null
            },
            ...
        ]
    },
    "errors": [
        {
            "path": [
                "allPosts",
                0,
                "relatedPosts"
            ],
            "errorType": "Lambda:Handled",
            "locations": [
                {
                    "line": 5,
                    "column": 5
                }
            ],
            "message": "I fail. Always."
        }
    ]
}
```

## Anwendungsfall für Fortgeschrittene: Batching
<a name="advanced-use-case-batching"></a>

Die Lambda-Funktion in diesem Beispiel hat ein `relatedPosts` Feld, das eine Liste verwandter Beiträge für einen bestimmten Beitrag zurückgibt. In den Beispielabfragen gibt der `allPosts` Feldaufruf der Lambda-Funktion fünf Beiträge zurück. Da wir angegeben haben, dass wir auch `relatedPosts` für jeden zurückgegebenen Beitrag eine Auflösung durchführen möchten, wird die `relatedPosts` Feldoperation fünfmal aufgerufen.

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

Das klingt in diesem speziellen Beispiel vielleicht nicht wesentlich, aber dieses verstärkte Überabrufen kann die Anwendung schnell untergraben.

Wenn wir z. B. in derselben Abfrage erneut `relatedPosts` für die zurückgegebenen verwandten `Posts` abrufen würden, würde die Anzahl der Abrufe dramatisch ansteigen.

```
query allPosts {
    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 dieser relativ einfachen Abfrage AWS AppSync würde die Lambda-Funktion 1 \$1 5 \$1 25 = 31 mal aufgerufen.

Dies ist eine häufig vorkommende Herausforderung, die oft als N\$11-Problem (in diesem Fall N = 5) bezeichnet wird und zu höherer Latenz und höheren Kosten für die Anwendung führen kann.

Ein Ansatz zur Lösung dieses Problems besteht darin, ähnliche Feld-Resolver-Anforderungen zu bündeln. In diesem Beispiel könnte die Lambda-Funktion, anstatt eine Liste verwandter Beiträge für einen bestimmten Beitrag auflösen zu lassen, stattdessen eine Liste verwandter Beiträge für einen bestimmten Stapel von Beiträgen auflösen.

Um dies zu demonstrieren, müssen wir den Resolver `Post.relatedPosts: [Post]` in einen stapelfähigen Resolver ändern.

Wählen Sie auf der rechten Seite der AWS AppSync Konsole den vorhandenen `Post.relatedPosts: [Post]` Resolver aus. Ändern Sie die Zuweisungsvorlage für Anforderungen wie folgt:

```
{
    "version": "2017-02-28",
    "operation": "BatchInvoke",
    "payload": {
        "field": "relatedPosts",
        "source":  $utils.toJson($context.source)
    }
}
```

Nur das Feld `operation` wurde von `Invoke` in `BatchInvoke` geändert. Das Payload-Feld wird jetzt zu einem Array mit allem, was in der Vorlage angegeben ist. In diesem Beispiel erhält die Lambda-Funktion Folgendes als Eingabe:

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

Wenn in der Vorlage für die Anforderungszuweisung angegeben `BatchInvoke` ist, empfängt die Lambda-Funktion eine Liste von Anfragen und gibt eine Ergebnisliste zurück.

Insbesondere muss die Ergebnisliste der Größe und Reihenfolge der Payload-Einträge der Anfrage entsprechen, damit die Ergebnisse entsprechend abgeglichen werden AWS AppSync können.

In diesem Batching-Beispiel gibt die Lambda-Funktion eine Reihe von Ergebnissen wie folgt zurück:

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

Die folgende Lambda-Funktion in Node.js demonstriert diese Batching-Funktionalität für das `Post.relatedPosts` Feld wie folgt:

```
exports.handler = (event, context, callback) => {
    console.log("Received event {}", JSON.stringify(event, 3));
    var 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"} };

    var relatedPosts = {
        "1": [posts['4']],
        "2": [posts['3'], posts['5']],
        "3": [posts['2'], posts['1']],
        "4": [posts['2'], posts['1']],
        "5": []
    };

    console.log("Got a BatchInvoke Request. The payload has %d items to resolve.", event.length);
    // event is now an array
    var field = event[0].field;
    switch(field) {
        case "relatedPosts":
            var results = [];
            // the response MUST contain the same number
            // of entries as the payload array
            for (var i=0; i< event.length; i++) {
                console.log("post {}", JSON.stringify(event[i].source));
                results.push(relatedPosts[event[i].source.id]);
            }
            console.log("results {}", JSON.stringify(results));
            callback(null, results);
            break;
        default:
            callback("Unknown field, unable to resolve" + field, null);
            break;
    }
};
```

### Rückgabe einzelner Fehler
<a name="returning-individual-errors"></a>

Die vorherigen Beispiele zeigen, dass es möglich ist, einen einzelnen Fehler von der Lambda-Funktion zurückzugeben oder einen Fehler aus den Mapping-Vorlagen auszulösen. Bei Batch-Aufrufen wird durch das Auslösen eines Fehlers über die Lambda-Funktion ein ganzer Batch als fehlgeschlagen gekennzeichnet. Dies kann für bestimmte Szenarien akzeptabel sein, in denen ein nicht behebbarer Fehler auftritt, z. B. eine fehlgeschlagene Verbindung zu einem Datenspeicher. In Fällen, in denen einige Elemente im Stapel erfolgreich sind und andere fehlschlagen, ist es jedoch möglich, sowohl Fehler als auch gültige Daten zurückzugeben. Da die Batch-Antwort AWS AppSync erfordert, um Elemente aufzulisten, die der ursprünglichen Größe des Stapels entsprechen, müssen Sie eine Datenstruktur definieren, die gültige Daten von fehlerhaften Daten unterscheiden kann.

*Wenn beispielsweise erwartet wird, dass die Lambda-Funktion einen Stapel verwandter Beiträge zurückgibt, könnten Sie sich dafür entscheiden, eine Liste von `Response` Objekten zurückzugeben, in der jedes Objekt optionale *Daten* -, *errorMessage* - und ErrorType-Felder hat.* Wenn das Feld *errorMessage* angezeigt wird, bedeutet dies, dass ein Fehler aufgetreten ist.

Der folgende Code zeigt, wie Sie die Lambda-Funktion aktualisieren können:

```
exports.handler = (event, context, callback) => {
    console.log("Received event {}", JSON.stringify(event, 3));
    var 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"} };

    var relatedPosts = {
        "1": [posts['4']],
        "2": [posts['3'], posts['5']],
        "3": [posts['2'], posts['1']],
        "4": [posts['2'], posts['1']],
        "5": []
    };

    console.log("Got a BatchInvoke Request. The payload has %d items to resolve.", event.length);
    // event is now an array
    var field = event[0].field;
    switch(field) {
        case "relatedPosts":
            var results = [];
            results.push({ 'data': relatedPosts['1'] });
            results.push({ 'data': relatedPosts['2'] });
            results.push({ 'data': null, 'errorMessage': 'Error Happened', 'errorType': 'ERROR' });
            results.push(null);
            results.push({ 'data': relatedPosts['3'], 'errorMessage': 'Error Happened with last result', 'errorType': 'ERROR' });
            callback(null, results);
            break;
        default:
            callback("Unknown field, unable to resolve" + field, null);
            break;
    }
};
```

In diesem Beispiel analysiert die folgende Antwortzuordnungsvorlage jedes Element der Lambda-Funktion und löst alle auftretenden Fehler aus:

```
#if( $context.result && $context.result.errorMessage )
    $utils.error($context.result.errorMessage, $context.result.errorType, $context.result.data)
#else
    $utils.toJson($context.result.data)
#end
```

Dieses Beispiel gibt eine GraphQL-Antwort ähnlich der folgenden aus:

```
{
  "data": {
    "allPosts": [
      {
        "id": "1",
        "relatedPostsPartialErrors": [
          {
            "id": "4",
            "title": "Fourth book"
          }
        ]
      },
      {
        "id": "2",
        "relatedPostsPartialErrors": [
          {
            "id": "3",
            "title": "Third book"
          },
          {
            "id": "5",
            "title": "Fifth book"
          }
        ]
      },
      {
        "id": "3",
        "relatedPostsPartialErrors": null
      },
      {
        "id": "4",
        "relatedPostsPartialErrors": null
      },
      {
        "id": "5",
        "relatedPostsPartialErrors": null
      }
    ]
  },
  "errors": [
    {
      "path": [
        "allPosts",
        2,
        "relatedPostsPartialErrors"
      ],
      "errorType": "ERROR",
      "locations": [
        {
          "line": 4,
          "column": 9
        }
      ],
      "message": "Error Happened"
    },
    {
      "path": [
        "allPosts",
        4,
        "relatedPostsPartialErrors"
      ],
      "data": [
        {
          "id": "2",
          "title": "Second book"
        },
        {
          "id": "1",
          "title": "First book"
        }
      ],
      "errorType": "ERROR",
      "locations": [
        {
          "line": 4,
          "column": 9
        }
      ],
      "message": "Error Happened with last result"
    }
  ]
}
```

### Konfiguration der maximalen Batchgröße
<a name="configure-max-batch-size"></a>

Standardmäßig werden bei der Verwendung `BatchInvoke` Anfragen AWS AppSync an Ihre Lambda-Funktion in Stapeln von bis zu fünf Elementen gesendet. Sie können die maximale Batchgröße Ihrer Lambda-Resolver konfigurieren.

Um die maximale Batchgröße auf einem Resolver zu konfigurieren, verwenden Sie den folgenden Befehl in der (): AWS Command Line Interface AWS CLI

```
$ aws appsync create-resolver --api-id <api-id> --type-name Query --field-name relatedPosts \
 --request-mapping-template "<template>" --response-mapping-template "<template>" --data-source-name "<lambda-datasource>" \ 
 --max-batch-size X
```

**Anmerkung**  
Wenn Sie eine Vorlage für die Anforderungszuweisung bereitstellen, müssen Sie den `BatchInvoke` Vorgang verwenden, um Batching zu verwenden.

Sie können auch den folgenden Befehl verwenden, um Batching auf Direct Lambda Resolvern zu aktivieren und zu konfigurieren:

```
$ aws appsync create-resolver --api-id <api-id> --type-name Query --field-name relatedPosts \
 --data-source-name "<lambda-datasource>" \ 
 --max-batch-size X
```

### Konfiguration der maximalen Batchgröße mit VTL-Vorlagen
<a name="configure-max-batch-size-vtl"></a>

Bei Lambda-Resolvern mit VTL-In-Request-Vorlagen hat die maximale Batchgröße keine Auswirkung, es sei denn, sie haben sie direkt als `BatchInvoke` Operation in VTL angegeben. Ebenso wird, wenn Sie eine Mutation der obersten Ebene durchführen, kein Batching für Mutationen durchgeführt, da die GraphQL-Spezifikation verlangt, dass parallel Mutationen sequentiell ausgeführt werden.

Nehmen wir zum Beispiel die folgenden Mutationen:

```
type Mutation {
    putItem(input: Item): Item
    putItems(inputs: [Item]): [Item]
}
```

Mit der ersten Mutation können wir 10 erstellen, `Items` wie im folgenden Ausschnitt gezeigt:

```
mutation MyMutation {
    v1: putItem($someItem1) {
        id,
        name
    }
    v2: putItem($someItem2) {
        id,
        name
    }
    v3: putItem($someItem3) {
        id,
        name
    } 
    v4: putItem($someItem4) {
        id,
        name
    }
    v5: putItem($someItem5) {
        id,
        name
    }
    v6: putItem($someItem6) {
        id,
        name
    } 
    v7: putItem($someItem7) {
        id,
        name
    }
    v8: putItem($someItem8) {
        id,
        name
    }
    v9: putItem($someItem9) {
        id,
        name
    }
    v10: putItem($someItem10) {
        id,
        name
    }
}
```

In diesem Beispiel `Items` werden die nicht in einer Gruppe von 10 gebündelt, auch wenn die maximale Batchgröße im Lambda Resolver auf 10 gesetzt ist. Stattdessen werden sie sequentiell gemäß der GraphQL-Spezifikation ausgeführt.

Um eine tatsächliche Batch-Mutation durchzuführen, können Sie dem folgenden Beispiel folgen und die zweite Mutation verwenden:

```
mutation MyMutation {
    putItems([$someItem1, $someItem2, $someItem3,$someItem4, $someItem5, $someItem6, 
    $someItem7, $someItem8, $someItem9, $someItem10]) {
    id,
    name
    }
}
```

Weitere Informationen zur Verwendung von Batching mit Direct Lambda Resolvern finden Sie unter. [Direkte Lambda-Resolver](resolver-mapping-template-reference-lambda.md#direct-lambda-resolvers)

# Verwendung von Amazon OpenSearch Service-Resolvern in AWS AppSync
<a name="tutorial-elasticsearch-resolvers"></a>

**Anmerkung**  
Wir unterstützen jetzt hauptsächlich die APPSYNC\$1JS-Laufzeit und ihre Dokumentation. [Bitte erwägen Sie, die APPSYNC\$1JS-Laufzeit und ihre Anleitungen hier zu verwenden.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

AWS AppSync unterstützt die Nutzung von Amazon OpenSearch Service von Domains aus, die Sie in Ihrem eigenen AWS Konto bereitgestellt haben, sofern sie nicht in einer VPC existieren. Nachdem Ihre Domänen bereitgestellt wurden, können Sie sich über eine Datenquelle mit ihnen verbinden. Zu diesem Zeitpunkt können Sie auch einen Resolver im Schema konfigurieren, um GraphQL-Operationen, wie z. B. Abfragen, Mutationen und Abonnements, auszuführen. Diese Anleitung führt Sie durch einige häufig auftretende Beispiele.

Weitere Informationen finden Sie in der [Resolver Mapping Template](resolver-mapping-template-reference-elasticsearch.md#aws-appsync-resolver-mapping-template-reference-elasticsearch) Reference für. OpenSearch

## One-Click-Setup
<a name="one-click-setup"></a>

Um automatisch einen GraphQL-Endpunkt AWS AppSync mit konfiguriertem Amazon OpenSearch Service einzurichten, können Sie diese AWS CloudFormation Vorlage verwenden:

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

Nach Abschluss der AWS CloudFormation Bereitstellung können Sie direkt mit der [Ausführung von GraphQL-Abfragen und -Mutationen fortfahren](#tutorial-elasticsearch-resolvers-perform-queries-mutations).

## Erstellen Sie eine neue OpenSearch Dienstdomäne
<a name="create-a-new-es-domain"></a>

Um mit diesem Tutorial beginnen zu können, benötigen Sie eine bestehende OpenSearch Dienstdomäne. Wenn Sie noch keine haben, können Sie das folgende Bespiel verwenden. Beachten Sie, dass es bis zu 15 Minuten dauern kann, bis eine OpenSearch Dienstdomäne erstellt ist, bevor Sie mit der Integration in eine AWS AppSync Datenquelle fortfahren können.

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

Sie können den folgenden AWS CloudFormation Stack in der Region USA West 2 (Oregon) in Ihrem AWS Konto starten:

 [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)

## Konfigurieren Sie die Datenquelle für den OpenSearch Service
<a name="configure-data-source-for-es"></a>

Nachdem die OpenSearch Service-Domain erstellt wurde, navigieren Sie zu Ihrer AWS AppSync GraphQL-API und wählen Sie die Registerkarte **Datenquellen**. Wählen Sie **Neu** und geben Sie einen benutzerfreundlichen Namen für die Datenquelle ein, z. B. „oss“. Wählen Sie dann ** OpenSearch Amazon-Domain** als **Datenquellentyp**, wählen Sie die entsprechende Region aus, und Ihre OpenSearch Service-Domain sollte aufgeführt sein. Nachdem Sie sie ausgewählt haben, können Sie entweder eine neue Rolle erstellen und ihnen AWS AppSync die entsprechenden Berechtigungen zuweisen, oder Sie können eine bestehende Rolle auswählen, für die die folgende Inline-Richtlinie gilt:

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

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Sid": "Stmt1234234",
            "Effect": "Allow",
            "Action": [
                "es:ESHttpDelete",
                "es:ESHttpHead",
                "es:ESHttpGet",
                "es:ESHttpPost",
                "es:ESHttpPut"
            ],
            "Resource": [
                "arn:aws:es:us-east-1:111122223333:domain/democluster/*"
            ]
        }
    ]
}
```

------

Sie müssen außerdem eine Vertrauensbeziehung AWS AppSync für diese Rolle einrichten mit:

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

****  

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

------

Darüber hinaus hat die OpenSearch Service-Domain ihre eigene **Zugriffsrichtlinie**, die Sie über die Amazon OpenSearch Service-Konsole ändern können. Sie müssen eine Richtlinie hinzufügen, die der folgenden ähnelt und die entsprechenden Aktionen und Ressourcen für die OpenSearch Service-Domain enthält. Beachten Sie, dass der **Principal** die AppSync Datenquellenrolle sein wird. Wenn Sie diese Rolle von der Konsole erstellen lassen, finden Sie diese Rolle in der IAM-Konsole.

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

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::111122223333:role/service-role/APPSYNC_DATASOURCE_ROLE"
            },
            "Action": [
                "es:ESHttpDelete",
                "es:ESHttpHead",
                "es:ESHttpGet",
                "es:ESHttpPost",
                "es:ESHttpPut"
            ],
            "Resource": "arn:aws:es:us-east-1:111122223333:domain/DOMAIN_NAME/*"
        }
    ]
}
```

------

## Verbinden eines Resolvers
<a name="connecting-a-resolver"></a>

Nachdem die Datenquelle nun mit Ihrer OpenSearch Service-Domain verbunden ist, können Sie sie mit einem Resolver mit Ihrem GraphQL-Schema verbinden, wie im folgenden Beispiel gezeigt:

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

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

Beachten Sie, dass es einen benutzerdefinierten `Post`-Typ mit einem `id`-Feld gibt. In den folgenden Beispielen gehen wir davon aus, dass es einen Prozess gibt (der automatisiert werden kann), um diesen Typ in Ihre OpenSearch Service-Domain einzufügen, der einem Pfadstamm von zugeordnet würde`/post/_doc`, wo sich der Index `post` befindet. Von diesem Stammpfad aus können Sie einzelne Dokumente, Platzhaltersuchen mit `/id/post*` oder Suchen in mehreren Dokumenten mit dem Pfad von durchführen. `/post/_search` Wenn Sie beispielsweise einen anderen Typ haben`User`, können Sie Dokumente unter einem neuen Index namens `user` indexieren und dann Suchen mit dem **Pfad** von durchführen. `/user/_search` 

Ändern Sie im Schema-Editor in der AWS AppSync Konsole das vorherige `Posts` Schema, sodass es eine `searchPosts` Abfrage enthält:

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

Speichern Sie das Schema. Wählen Sie auf der rechten Seite unter `searchPosts` die Option **Resolver anfügen (Attach resolver)** aus. Wählen Sie im **Menü Aktion** die Option **Laufzeit aktualisieren** und anschließend **Unit Resolver (nur VTL**) aus. Wählen Sie dann Ihre OpenSearch Service-Datenquelle aus. Wählen Sie im Bereich **Zuweisungsvorlage für Anforderungen (request mapping template)** die Dropdown-Liste für **Abfrageposten (Query posts)** aus, um eine Basisvorlage zu erhalten. Ändern Sie den `path` so ab, dass er `/post/_search` anzeigt. Sie sollte wie folgt aussehen:

```
{
    "version":"2017-02-28",
    "operation":"GET",
    "path":"/post/_search",
    "params":{
        "headers":{},
        "queryString":{},
        "body":{
            "from":0,
            "size":50
        }
    }
}
```

Dabei wird davon ausgegangen, dass das obige Schema Dokumente enthält, die in OpenSearch Service unter dem `post` Feld indexiert wurden. Wenn Sie Ihre Daten anders strukturieren, müssen Sie eine entsprechende Anpassung durchführen.

Im Abschnitt **Antwortzuordnungsvorlage** müssen Sie den entsprechenden `_source` Filter angeben, wenn Sie die Datenergebnisse einer OpenSearch Serviceabfrage abrufen und in GraphQL übersetzen möchten. Verwenden Sie die folgende Vorlage:

```
[
    #foreach($entry in $context.result.hits.hits)
    #if( $velocityCount > 1 ) , #end
    $utils.toJson($entry.get("_source"))
    #end
]
```

## Ändern Ihrer Suchvorgänge
<a name="modifying-your-searches"></a>

Die vorherige Zuweisungsvorlage für Anforderungen führt eine einfache Abfrage aller Datensätze aus. Angenommen, Sie möchten nach einem bestimmten Autor suchen. Nehmen wir darüber hinaus noch an, Sie möchten, dass dieser Autor in Ihrer GraphQL-Abfrage als Argument definiert ist. Fügen Sie nun im Schema-Editor der AWS AppSync-Konsole eine `allPostsByAuthor`-Abfrage hinzu:

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

Wählen Sie nun **Attach Resolver** und wählen Sie die OpenSearch Service-Datenquelle aus. Verwenden Sie jedoch das folgende Beispiel in der **Antwortzuordnungsvorlage**:

```
{
    "version":"2017-02-28",
    "operation":"GET",
    "path":"/post/_search",
    "params":{
        "headers":{},
        "queryString":{},
        "body":{
            "from":0,
            "size":50,
            "query":{
                "match" :{
                    "author": $util.toJson($context.arguments.author)
                }
            }
        }
    }
}
```

Beachten Sie, dass der `body` mit einer Begriffsabfrage für das `author`-Feld ausgefüllt wurde und vom Client als Argument übergeben wurde. Sie könnten optional bereits ausgefüllte Informationen, wie z. B. einen Standardtext, oder sogar andere [Dienstprogramme](resolver-context-reference.md#aws-appsync-resolver-mapping-template-context-reference) verwenden.

Wenn Sie diesen Resolver verwenden möchten, füllen Sie die **Zuweisungsvorlage für Antworten** mit den gleichen Informationen aus, wie im vorherigen Beispiel gezeigt.

## Daten zum OpenSearch Dienst hinzufügen
<a name="adding-data-to-es"></a>

Möglicherweise möchten Sie Ihrer OpenSearch Service-Domain aufgrund einer GraphQL-Mutation Daten hinzufügen. Hierbei handelt es sich um einen äußerst effektiven Mechanismus für Suchvorgänge und andere Zwecke. Da Sie GraphQL-Abonnements verwenden können, um [Ihre Daten in Echtzeit zu erstellen](aws-appsync-real-time-data.md), dient es als Mechanismus, um Clients über Aktualisierungen von Daten in Ihrer OpenSearch Service-Domain zu informieren.

Kehren Sie zur **Schemaseite** in der AWS AppSync Konsole zurück und wählen Sie **Attach Resolver** für die Mutation aus. `addPost()` Wählen Sie erneut die OpenSearch Service-Datenquelle aus und verwenden Sie die folgende **Antwortzuordnungsvorlage** für das `Posts` Schema:

```
{
    "version":"2017-02-28",
    "operation":"PUT",
    "path": $util.toJson("/post/_doc/$context.arguments.id"),
    "params":{
        "headers":{},
        "queryString":{},
        "body":{
            "id": $util.toJson($context.arguments.id),
            "author": $util.toJson($context.arguments.author),
            "ups": $util.toJson($context.arguments.ups),
            "downs": $util.toJson($context.arguments.downs),
            "url": $util.toJson($context.arguments.url),
            "content": $util.toJson($context.arguments.content),
            "title": $util.toJson($context.arguments.title)
        }
    }
}
```

Wie zuvor ist dies nur ein Beispiel dafür, wie Ihre Daten strukturiert sein könnten. Wenn Sie über andere Feldnamen oder Indizes verfügen, müssen Sie den `path` und `body` entsprechend anpassen. Dieses Beispiel zeigt auch, wie Sie `$context.arguments` verwenden, um die Vorlage mit den GraphQL-Mutationsargumenten zu füllen.

Bevor Sie fortfahren, verwenden Sie die folgende Antwortzuordnungsvorlage, die das Ergebnis der Mutationsoperation oder Fehlerinformationen als Ausgabe zurückgibt:

```
#if($context.error)
    $util.toJson($ctx.error)
#else
    $util.toJson($context.result)
#end
```

## Abrufen eines einzelnen Dokuments
<a name="retrieving-a-single-document"></a>

Sofern Sie die `getPost(id:ID)`-Abfrage im Schema verwenden möchten, um ein einzelnes Dokument zurückzugeben, suchen Sie diese Abfrage im Schema-Editor der AWS AppSync-Konsole und wählen Sie **Attach resolver (Resolver anfügen)** aus. Wählen Sie erneut die OpenSearch Service-Datenquelle aus und verwenden Sie die folgende Zuordnungsvorlage:

```
{
    "version":"2017-02-28",
    "operation":"GET",
    "path": $util.toJson("post/_doc/$context.arguments.id"),
    "params":{
        "headers":{},
        "queryString":{},
        "body":{}
    }
}
```

Da der oben genannte `path` das `id`-Argument ohne Text verwendet, wird auf diese Weise ein einzelnes Dokument zurückgegeben. Jedoch müssen Sie die folgende Zuweisungsvorlage für Antworten verwenden, da Sie jetzt ein einzelnes Element und keine Liste zurückgeben:

```
$utils.toJson($context.result.get("_source"))
```

## Ausführen von Abfragen und Mutationen
<a name="tutorial-elasticsearch-resolvers-perform-queries-mutations"></a>

Sie sollten jetzt in der Lage sein, GraphQL-Operationen für Ihre OpenSearch Service-Domain durchzuführen. Navigieren Sie zur Registerkarte **Abfragen** der AWS AppSync Konsole und fügen Sie einen neuen Datensatz hinzu:

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

Sie werden das Ergebnis der Mutation auf der rechten Seite sehen. In ähnlicher Weise können Sie jetzt eine `searchPosts` Abfrage für Ihre OpenSearch Service-Domain ausführen:

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

## Bewährte Methoden
<a name="best-practices"></a>
+ OpenSearch Der Dienst sollte zum Abfragen von Daten dienen, nicht als primäre Datenbank. Möglicherweise möchten Sie OpenSearch Service in Verbindung mit Amazon DynamoDB verwenden, wie unter [Kombinieren von GraphQL-Resolvern](tutorial-combining-graphql-resolvers.md#aws-appsync-tutorial-combining-graphql-resolvers) beschrieben.
+ Gewähren Sie nur Zugriff auf Ihre Domain, indem Sie der AWS AppSync Servicerolle den Zugriff auf den Cluster gestatten.
+ Sie können mit dieser Entwicklung klein anfangen, indem Sie zunächst nur den preisgünstigsten Cluster verwenden, und später während der Produktion zu einem größeren Cluster überwechseln, der über eine hohe Verfügbarkeit verfügt.

# Verwendung lokaler Resolver in AWS AppSync
<a name="tutorial-local-resolvers"></a>

**Anmerkung**  
Wir unterstützen jetzt hauptsächlich die APPSYNC\$1JS-Laufzeit und ihre Dokumentation. [Bitte erwägen Sie, die APPSYNC\$1JS-Laufzeit und ihre Anleitungen hier zu verwenden.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

AWS AppSync ermöglicht es Ihnen AWS Lambda, unterstützte Datenquellen (Amazon DynamoDB oder Amazon OpenSearch Service) für verschiedene Operationen zu verwenden. Doch in bestimmten Szenarien ist ein Aufruf an eine unterstützte Datenquelle möglicherweise nicht erforderlich.

Hier ist der lokale Resolver nützlich. Anstatt eine Remote-Datenquelle aufzurufen, **leitet** der lokale Resolver das Ergebnis der Zuweisungsvorlage für Anforderungen einfach an die Zuweisungsvorlage für Antworten weiter. Das Feldauflösung verlässt AWS AppSync nicht.

Lokale Resolver sind für verschiedene Anwendungsfälle nützlich. Der beliebtest Anwendungsfall ist das Veröffentlichen von Benachrichtigungen ohne Auslösen eines Datenquellenaufrufs. Um diesen Anwendungsfall zu demonstrieren, erstellen wir eine Paging-Anwendung; bei der Benutzer sich gegenseitig pagen können. In diesem Beispiel werden *Abonnements* verwendet. Wenn Sie noch nicht mit *Abonnements* vertraut sind, sehen Sie sich das Tutorial [Echtzeitdaten](aws-appsync-real-time-data.md) an.

## Erstellen der Paging-Anwendung
<a name="create-the-paging-application"></a>

In unserer Paging-Anwendung können Clients einen Posteingang abonnieren und Seiten an andere Clients senden. Jede Seite enthält eine Nachricht. Hier wird das Schema gezeigt:

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

type Subscription {
    inbox(to: String!): Page
    @aws_subscribe(mutations: ["page"])
}

type Mutation {
    page(body: String!, to: String!): Page!
}

type Page {
    from: String
    to: String!
    body: String!
    sentAt: String!
}

type Query {
    me: String
}
```

Hängen wir nun einen Resolver an das `Mutation.page`-Feld an. Klicken Sie im Bereich **Schema** auf *Attach Resolver (Resolver anhängen)* neben der Felddefinition auf dem rechten Bereich. Erstellen Sie eine neue Datenquelle vom Typ *Keine* und geben Sie ihr einen Namen. *PageDataSource*

Geben Sie für die Zuweisungsvorlage für Anforderungen Folgendes ein:

```
{
  "version": "2017-02-28",
  "payload": {
    "body": $util.toJson($context.arguments.body),
    "from": $util.toJson($context.identity.username),
    "to":  $util.toJson($context.arguments.to),
    "sentAt": "$util.time.nowISO8601()"
  }
}
```

Und wählen Sie für die Zuweisungsvorlage für Antworten die Standardoption *Forward the result (Ergebnis weiterleiten)* aus. Speichern Sie Ihren Resolver. Ihre Anwendung ist nun bereit, beginnen wir mit dem Pagen\$1

## Senden an und Abonnieren von Seiten
<a name="send-and-subscribe-to-pages"></a>

Damit Clients Seiten empfangen können, müssen sie zuerst einen Posteingang abonnieren.

Führen wir im Bereich **Queries (Abfragen)** das `inbox`-Abonnement aus:

```
subscription Inbox {
    inbox(to: "Nadia") {
        body
        to
        from
        sentAt
    }
}
```

 *Nadia* erhält Seiten, wann immer die `Mutation.page`-Mutation aufgerufen wird. Rufen wir nun die Mutation durch Ausführen der Mutation auf:

```
mutation Page {
    page(to: "Nadia", body: "Hello, World!") {
        body
        to
        from
        sentAt
    }
}
```

Wir haben gerade die Verwendung von lokalen Resolvern gezeigt, indem wir eine Seite gesendet und sie empfangen haben, ohne AWS AppSync zu verlassen.

# Kombinieren von GraphQL-Resolvern in AWS AppSync
<a name="tutorial-combining-graphql-resolvers"></a>

**Anmerkung**  
Wir unterstützen jetzt hauptsächlich die APPSYNC\$1JS-Laufzeit und ihre Dokumentation. [Bitte erwägen Sie, die APPSYNC\$1JS-Laufzeit und ihre Anleitungen hier zu verwenden.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

Resolver und Felder in einem GraphQL-Schema zeichnen sich durch 1-zu-1-Beziehungen mit einem hohen Maß an Flexibilität aus. Da eine Datenquelle auf einem Resolver unabhängig vom Schema konfiguriert wird, haben Sie die Möglichkeit, GraphQL-Typen über verschiedene Datenquellen aufzulösen oder zu manipulieren. Dabei spielt die Kombination des Schemas keine Rolle und kann sich ganz nach Ihren Anforderungen richten.

Die folgenden Beispielszenarien zeigen, wie Sie Datenquellen in Ihrem Schema kombinieren und abgleichen können. Bevor Sie beginnen, empfehlen wir, dass Sie mit der Einrichtung von Datenquellen und Resolvern für AWS Lambda Amazon DynamoDB und Amazon OpenSearch Service vertraut sind, wie in den vorherigen Tutorials beschrieben.

## Beispielschema
<a name="example-schema"></a>

Das folgende Schema hat einen Typ `Post` mit 3 `Query` Operationen und 3 definierten `Mutation` Operationen:

```
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 diesem Beispiel müssten Sie insgesamt 6 Resolver anfügen. Eine Möglichkeit wäre, all diese Daten aus einer Amazon DynamoDB-Tabelle mit dem Namen`Posts`, zu beziehen, in der ein Scan und `searchPosts` eine Abfrage `AllPosts` ausgeführt werden, wie in der [DynamoDB Resolver](resolver-mapping-template-reference-dynamodb.md#aws-appsync-resolver-mapping-template-reference-dynamodb) Mapping Template Reference beschrieben. Es gibt jedoch Alternativen, um Ihre Geschäftsanforderungen zu erfüllen, z. B. die Auflösung dieser GraphQL-Abfragen von Lambda oder OpenSearch Service.

## Ändern von Daten mithilfe von Resolvern
<a name="alter-data-through-resolvers"></a>

Möglicherweise müssen Sie Ergebnisse aus einer Datenbank wie DynamoDB (oder Amazon Aurora) an Clients zurückgeben, wobei einige der Attribute geändert wurden. Dies kann mit der Formatierung der Datentypen (z. B. Zeitstempeldifferenzen der Clients) oder mit Problemen bei der Handhabung der Rückwärtskompatibilität in Zusammenhang stehen. Zur Veranschaulichung manipuliert im folgenden Beispiel eine AWS Lambda Funktion die positiven und negativen Stimmen für Blogbeiträge, indem sie ihnen bei jedem Aufruf des GraphQL-Resolvers Zufallszahlen zuweist:

```
'use strict';
const doc = require('dynamodb-doc');
const dynamo = new doc.DynamoDB();

exports.handler = (event, context, callback) => {
    const payload = {
        TableName: 'Posts',
        Limit: 50,
        Select: 'ALL_ATTRIBUTES',
    };

    dynamo.scan(payload, (err, data) => {
        const result = { data: data.Items.map(item =>{
            item.ups = parseInt(Math.random() * (50 - 10) + 10, 10);
            item.downs = parseInt(Math.random() * (20 - 0) + 0, 10);
            return item;
        }) };
        callback(err, result.data);
    });
};
```

Hierbei handelt es sich um eine absolut gültige Lambda-Funktion, die dem `AllPosts`-Feld im GraphQL-Schema zugewiesen werden könnte. Auf diese Weise würde jeder Abfrage, die alle Ergebnisse zurückgibt, Zufallszahlen für die positiven und negativen Stimmen vergeben.

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

Bei einigen Anwendungen führen Sie möglicherweise Mutationen oder einfache Suchabfragen für DynamoDB durch und lassen einen Hintergrundprozess Dokumente an OpenSearch Service übertragen. Anschließend können Sie den `searchPosts` Resolver einfach an die OpenSearch Service-Datenquelle anhängen und Suchergebnisse (aus Daten, die ihren Ursprung in DynamoDB haben) mithilfe einer GraphQL-Abfrage zurückgeben. Dies kann äußerst hilfreich sein, wenn Sie Ihren Anwendungen erweiterte Suchfunktionen hinzufügen, beispielsweise Schlüsselwort-, Fuzzy- oder sogar raumbezogene Suchen. Die Übertragung von Daten aus DynamoDB kann über einen ETL-Prozess erfolgen, oder Sie können alternativ mithilfe von Lambda aus DynamoDB streamen. Sie können ein vollständiges Beispiel dafür starten, indem Sie den folgenden AWS CloudFormation Stack in der Region USA West 2 (Oregon) in Ihrem Konto verwenden: AWS 

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

Mit dem Schema in diesem Beispiel können Sie Beiträge mithilfe eines DynamoDB-Resolvers wie folgt hinzufügen:

```
mutation add {
    putPost(author:"Nadia"
        title:"My first post"
        content:"This is some test content"
        url:"https://aws.amazon.com/appsync/"
    ){
        id
        title
    }
}
```

Dadurch werden Daten in DynamoDB geschrieben, das dann Daten über Lambda an Amazon OpenSearch Service streamt, wo Sie nach allen Beiträgen anhand verschiedener Felder suchen können. Da sich die Daten beispielsweise in Amazon OpenSearch Service befinden, können Sie entweder die Autoren- oder Inhaltsfelder mit Freiformtext, auch mit Leerzeichen, wie folgt durchsuchen:

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

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

Da die Daten direkt in DynamoDB geschrieben werden, können Sie mit den Abfragen `allPosts{...}` und `singlePost{...}` dennoch effiziente Listen- oder Element-Suchvorgänge für die Tabelle durchführen. Dieser Stack verwendet den folgenden Beispielcode für DynamoDB-Streams:

 **Hinweis:** Dieser Code dient nur der Veranschaulichung.

```
var AWS = require('aws-sdk');
var path = require('path');
var stream = require('stream');

var esDomain = {
    endpoint: 'https://opensearch-domain-name.REGION.es.amazonaws.com',
    region: 'REGION',
    index: 'id',
    doctype: 'post'
};

var endpoint = new AWS.Endpoint(esDomain.endpoint)
var creds = new AWS.EnvironmentCredentials('AWS');

function postDocumentToES(doc, context) {
    var req = new AWS.HttpRequest(endpoint);

    req.method = 'POST';
    req.path = '/_bulk';
    req.region = esDomain.region;
    req.body = doc;
    req.headers['presigned-expires'] = false;
    req.headers['Host'] = endpoint.host;

    // Sign the request (Sigv4)
    var signer = new AWS.Signers.V4(req, 'es');
    signer.addAuthorization(creds, new Date());

    // Post document to ES
    var send = new AWS.NodeHttpClient();
    send.handleRequest(req, null, function (httpResp) {
        var body = '';
        httpResp.on('data', function (chunk) {
            body += chunk;
        });
        httpResp.on('end', function (chunk) {
            console.log('Successful', body);
            context.succeed();
        });
    }, function (err) {
        console.log('Error: ' + err);
        context.fail();
    });
}

exports.handler = (event, context, callback) => {
    console.log("event => " + JSON.stringify(event));
    var posts = '';

    for (var i = 0; i < event.Records.length; i++) {
        var eventName = event.Records[i].eventName;
        var actionType = '';
        var image;
        var noDoc = false;
        switch (eventName) {
            case 'INSERT':
                actionType = 'create';
                image = event.Records[i].dynamodb.NewImage;
                break;
            case 'MODIFY':
                actionType = 'update';
                image = event.Records[i].dynamodb.NewImage;
                break;
            case 'REMOVE':
            actionType = 'delete';
                image = event.Records[i].dynamodb.OldImage;
                noDoc = true;
                break;
        }

        if (typeof image !== "undefined") {
            var postData = {};
            for (var key in image) {
                if (image.hasOwnProperty(key)) {
                    if (key === 'postId') {
                        postData['id'] = image[key].S;
                    } else {
                        var val = image[key];
                        if (val.hasOwnProperty('S')) {
                            postData[key] = val.S;
                        } else if (val.hasOwnProperty('N')) {
                            postData[key] = val.N;
                        }
                    }
                }
            }

            var action = {};
            action[actionType] = {};
            action[actionType]._index = 'id';
            action[actionType]._type = 'post';
            action[actionType]._id = postData['id'];
            posts += [
                JSON.stringify(action),
            ].concat(noDoc?[]:[JSON.stringify(postData)]).join('\n') + '\n';
        }
    }
    console.log('posts:',posts);
    postDocumentToES(posts, context);
};
```

Sie können dies dann mithilfe von DynamoDB-Streams an eine DynamoDB-Tabelle mit dem Primärschlüssel von anhängen`id`, und alle Änderungen an der DynamoDB-Quelle würden in Ihre Service-Domain gestreamt. OpenSearch Weitere Informationen zum Konfigurieren dieser Einstellung finden Sie in der [Dokumentation zu DynamoDB Streams](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.Lambda.html).

# Verwenden von DynamoDB-Batchoperationen in AWS AppSync
<a name="tutorial-dynamodb-batch"></a>

**Anmerkung**  
Wir unterstützen jetzt hauptsächlich die APPSYNC\$1JS-Laufzeit und ihre Dokumentation. [Bitte erwägen Sie, die APPSYNC\$1JS-Laufzeit und ihre Anleitungen hier zu verwenden.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

AWS AppSync unterstützt die Verwendung von Amazon DynamoDB-Batchoperationen für eine oder mehrere Tabellen in einer einzigen Region. Zu den unterstützten Vorgängen gehören `BatchGetItem`, `BatchPutItem` und `BatchDeleteItem`. Durch die Verwendung dieser Funktionen in AWS AppSync können Sie beispielsweise folgende Aufgaben ausführen:
+ Übermitteln einer Liste von Schlüsseln in einer einzigen Abfrage und Zurückgabe der Ergebnisse aus einer Tabelle
+ Lesen der Datensätze aus einer oder mehrerer Tabellen in einer einzigen Abfrage
+ Schreiben von Datensätzen in großen Mengen in einer oder mehreren Tabellen
+ Bedingtes Schreiben oder Löschen von Datensätzen in mehreren Tabellen, zwischen denen möglicherweise eine Beziehung besteht

Die Verwendung von Batch-Operationen mit DynamoDB AWS AppSync ist eine fortgeschrittene Technik, die etwas mehr Nachdenken und Wissen über Ihre Backend-Operationen und Tabellenstrukturen erfordert. Darüber hinaus AWS AppSync weisen Batch-Operationen zwei wesentliche Unterschiede zu Vorgängen ohne Batch auf:
+ Die Rolle der Datenquelle muss über Berechtigungen für alle Tabellen verfügen, auf die Resolver zugreifen wird.
+ Die Tabellenangaben für einen Resolver sind Teil der Zuweisungsvorlage.

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

Wie bei anderen Resolvern müssen Sie eine Datenquelle in erstellen AWS AppSync und entweder eine Rolle erstellen oder eine vorhandene verwenden. Da Batchoperationen unterschiedliche Berechtigungen für DynamoDB-Tabellen erfordern, müssen Sie den konfigurierten Rollen Berechtigungen für Lese- oder Schreibaktionen gewähren:

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

****  

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

------

 **Hinweis**: Rollen sind an Datenquellen in einer Datenquelle gebunden AWS AppSync, und Resolver für Felder werden für eine Datenquelle aufgerufen. Für Datenquellen, die für den Abruf von DynamoDB konfiguriert sind, ist nur eine Tabelle angegeben, um die Konfiguration zu vereinfachen. Möchten Sie jedoch einen Stapelvorgang an mehreren Tabellen mit nur einem Resolver ausführen, stellt dies eine erweiterte Aufgabe dar und Sie müssen der Rolle dieser Datenquelle Zugriff auf alle Tabellen gewähren, mit denen der Resolver interagieren wird. Dies kann im Feld **Ressource (Resource)** in der IAM-Richtlinie weiter oben eingerichtet werden. Die Konfiguration der Tabellen, um Stapelaufrufe auszuführen, erfolgt in der Resolver-Vorlage und wird nachfolgend beschrieben.

## Datenquelle
<a name="data-source"></a>

Der Einfachheit halber verwenden wir die gleiche Datenquelle für alle in diesem Tutorial verwendeten Resolver. Erstellen Sie auf der Registerkarte **Datenquellen** eine neue DynamoDB-Datenquelle und geben Sie ihr einen Namen. **BatchTutorial** Sie können den Namen der Tabelle frei wählen, da Tabellennamen als Teil der Zuweisungsvorlage für Anforderungen bei Stapelvorgängen angegeben werden. Wir geben der Tabelle den Namen `empty`.

Für diese Anleitung kann jede Rolle mit der folgenden eingebundene Richtlinie verwendet werden:

## Stapelvorgang mit einer Tabelle
<a name="single-table-batch"></a>

**Warnung**  
`BatchPutItem`und `BatchDeleteItem` werden nicht unterstützt, wenn sie zusammen mit der Konflikterkennung und -lösung verwendet werden. Diese Einstellungen müssen deaktiviert werden, um mögliche Fehler zu vermeiden.

In diesem Beispiel gehen wir davon aus, dass Sie über eine einzelne Tabelle mit dem Namen **Posts** verfügen, zu der Sie anhand von Stapelvorgängen Elemente hinzufügen bzw. von der Sie Elemente entfernen möchten. Verwenden Sie das folgende Schema und beachten Sie, dass wir für die Abfrage eine Liste mit folgenden Elementen übergeben IDs:

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

input PostInput {
    id: ID!
    title: String
}

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

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

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

Fügen Sie dem Feld `batchAdd()` mithilfe der folgenden **Zuweisungsvorlage für Anforderungen** einen Resolver an. Hierdurch wird automatisch jedes Element im GraphQL- `input PostInput`-Typ berücksichtigt und eine Zuordnung erstellt, wie sie für die `BatchPutItem`-Operation erforderlich ist:

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

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

In diesem Fall handelt es sich bei der **Zuweisungsvorlage für Antworten** um einen einfachen Pass-Through. Beachten Sie jedoch, dass der Tabellenname als `..data.Posts` an das Kontextobjekt angefügt wird:

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

Navigieren Sie jetzt zur Seite **Queries (Abfragen)** der AWS AppSync-Konsole und führen Sie die folgende **batchAdd**-Mutation aus:

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

Sie sollten die Ergebnisse auf dem Bildschirm sehen und können unabhängig voneinander über die DynamoDB-Konsole überprüfen, ob beide Werte in die Tabelle **Posts** geschrieben wurden.

Fügen Sie als Nächstes dem Feld `batchGet()` mithilfe der folgenden **Zuweisungsvorlage für Anforderungen** einen Resolver an. Hierdurch wird automatisch jedes Element im GraphQL `ids:[]`-Typ berücksichtigt und eine Zuordnung erstellt, wie sie für die `BatchGetItem`-Operation erforderlich ist:

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

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

In diesem Fall handelt es sich bei der **Zuweisungsvorlage für Anforderungen** wiederum um einen einfachen Pass-Through, dem erneut dem Context-Objekt des Tabellennamens `..data.Posts` angefügt wurde:

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

Navigieren Sie wieder zur Seite **Queries (Abfragen)** der AWS AppSync-Konsole und führen Sie die folgende **batchGet-Abfrage** aus:

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

Dies sollte die Ergebnisse für die beiden `id`-Werte, die Sie zuvor hinzugefügt haben, zurückgeben. Beachten Sie, dass ein `null`-Wert für die `id` mit einem Wert von `3` zurückgegeben wurde. Das liegt daran, dass bisher noch kein Datensatz mit diesem Wert in Ihrer **Posts**-Tabelle vorhanden war. Beachten Sie auch, dass die Ergebnisse in derselben Reihenfolge AWS AppSync zurückgegeben werden wie die an die Abfrage übergebenen Schlüssel. Dies ist eine zusätzliche Funktion, die in Ihrem AWS AppSync Namen ausgeführt wird. Wenn Sie jetzt zu `batchGet(ids:[1,3,2)` wechseln, sehen Sie, dass sich die Reihenfolge geändert hat. Sie können darüber hinaus erkennen, welche `id` einen `null`-Wert zurückgegeben hat.

Fügen Sie zum Schluss dem Feld `batchDelete()` mithilfe der folgenden **Zuweisungsvorlage für Anforderungen** einen Resolver an. Hierdurch wird automatisch jedes Element im GraphQL `ids:[]`-Typ berücksichtigt und eine Zuordnung erstellt, wie sie für die `BatchGetItem`-Operation erforderlich ist:

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

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

In diesem Fall handelt es sich bei der **Zuweisungsvorlage für Anforderungen** wiederum um einen einfachen Pass-Through, dem erneut dem Context-Objekt des Tabellennamens `..data.Posts` angefügt wurde:

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

Navigieren Sie jetzt zurück zur Seite **Queries (Abfragen)** der AWS AppSync-Konsole und führen Sie die folgende **batchDelete**-Mutation aus:

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

Die Datensätze mit der `id` `1` und `2` sollten jetzt gelöscht sein. Wenn Sie die frühere `batchGet()`-Abfrage ausführen, sollten diese `null` zurückgeben.

## Stapelvorgang mit mehreren Tabellen
<a name="multi-table-batch"></a>

**Warnung**  
`BatchPutItem`und `BatchDeleteItem` werden nicht unterstützt, wenn sie zusammen mit der Konflikterkennung und -lösung verwendet werden. Diese Einstellungen müssen deaktiviert werden, um mögliche Fehler zu vermeiden.

AWS AppSync ermöglicht es Ihnen auch, tabellenübergreifende Batch-Operationen durchzuführen. Lassen Sie uns hierzu eine komplexere Anwendung erstellen. Stellen Sie sich vor, wir entwickeln eine Gesundheits-App für Haustiere, bei der Sensoren den Standort und die Körpertemperatur der Tiere aufzeichnen. Diese Sensoren sind batteriebetrieben und versuchen, alle paar Minuten eine Verbindung mit dem Netzwerk aufzubauen. Wenn ein Sensor eine Verbindung herstellt, sendet er seine Messwerte an unsere AWS AppSync API. Die Daten werden von Auslösern analysiert und dem Besitzer des Haustiers in einem Dashboard angezeigt. Lassen Sie uns jetzt die Interaktionen zwischen dem Sensor und dem Backend-Datenspeicher näher untersuchen.

Als Voraussetzung erstellen wir zunächst zwei DynamoDB-Tabellen. LocationReadings speichert **Sensorstandortwerte** und **TemperatureReadings speichert Sensortemperaturwerte**. Beide Tabellen haben zufällig die gleiche Primärschlüsselstruktur: `sensorId (String)` als der Partitionsschlüssel und `timestamp (String)` als der Sortierschlüssel.

Verwenden wir das folgende GraphQL-Schema:

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

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

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

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

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

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

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

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

### BatchPutItem - Aufzeichnen von Sensormesswerten
<a name="batchputitem-recording-sensor-readings"></a>

Nachdem eine Verbindung zum Internet hergestellt wurde, müssen unsere Sensoren in der Lage sein, ihre Messwerte zu senden. Sie verwenden dazu die API GraphQL-Feld `Mutation.recordReadings`. Um unsere API in Betrieb nehmen zu können, müssen wir zunächst einen Resolver anfügen.

Wählen Sie hierzu **Anfügen (Attach)** neben dem Feld `Mutation.recordReadings` aus. Wählen Sie auf dem nächsten Bildschirm die gleiche `BatchTutorial`-Datenquelle wie zu Beginn dieser Anleitung aus.

Fügen Sie die folgende Zuweisungsvorlage für Anforderungen hinzu.

 **Zuweisungsvorlage für Anforderungen** 

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

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

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

Wie Sie sehen, können wir über die `BatchPutItem`-Operation mehrere Tabellen angeben.

Verwenden Sie die folgende Zuweisungsvorlage für Antworten.

 **Zuweisungsvorlage für Antworten** 

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

Bei Stapelvorgängen können durch den Aufruf sowohl Fehler als auch Ergebnisse zurückgegeben werden. In diesem Fall können wir eine zusätzliche Fehlerbehandlung vornehmen.

 **Hinweis**: Die Verwendung von `$utils.appendError()` lässt sich mit `$util.error()` vergleichen, mit dem großen Unterschied, dass die Bewertung der Zuweisungsvorlage nicht unterbrochen wird. Stattdessen wird signalisiert, dass das Feld zwar eine Fehlermeldung hervorrief, die Beurteilung der Vorlage jedoch abgeschlossen wurde und infolgedessen die Daten wieder an den Aufrufer zurückgegeben werden konnten. Wir empfehlen Ihnen die Verwendung von `$utils.appendError()`, wenn Ihrer Anwendung zumindest Teilergebnisse zurückgegeben werden müssen.

Speichern Sie den Resolver und navigieren Sie zur **Abfrageseite** der AWS AppSync Konsole. Senden wir jetzt einige Sensormesswerte.

Führen Sie die folgende Mutation aus:

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

Wir werden 10 Sensormesswerte in einer Mutation senden, wobei die Messwerte in zwei Tabellen aufgeteilt sind. **Verwenden Sie die DynamoDB-Konsole, um zu überprüfen, ob Daten sowohl in den **LocationReadings** - als auch in den TemperatureReadings-Tabellen angezeigt werden.**

### BatchDeleteItem - Löschen von Sensormesswerten
<a name="batchdeleteitem-deleting-sensor-readings"></a>

Gleichzeitig müssen wir auch Stapel mit Sensormesswerten löschen können. Dazu verwenden wir das GraphQL-Feld `Mutation.deleteReadings`. Wählen Sie hierzu **Anfügen (Attach)** neben dem Feld `Mutation.recordReadings` aus. Wählen Sie auf dem nächsten Bildschirm die gleiche `BatchTutorial`-Datenquelle wie zu Beginn dieser Anleitung aus.

Verwenden Sie die folgende Zuweisungsvorlage für Anforderungen.

 **Zuweisungsvorlage für Anforderungen** 

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

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

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

Die Zuweisungsvorlage für Antworten ist die gleiche, die wir bereits für `Mutation.recordReadings` verwendet haben.

 **Zuweisungsvorlage für Antworten** 

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

Speichern Sie den Resolver und navigieren Sie zur **Abfrageseite** der AWS AppSync Konsole. Lassen Sie uns jetzt einige der Sensormesswerte löschen\$1

Führen Sie die folgende Mutation aus:

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

**Überprüfen Sie über die DynamoDB-Konsole, ob diese beiden Messwerte aus den Tabellen **LocationReadings und TemperatureReadings** gelöscht wurden.**

### BatchGetItem - Messwerte abrufen
<a name="batchgetitem-retrieve-readings"></a>

Eine weitere gängige Operation für unsere Gesundheits-App für Haustiere bestünde darin, die Messwerte eines Sensors zu einem bestimmten Zeitpunkt abzurufen. Fügen wir dazu einen Resolver zum GraphQL-Feld `Query.getReadings` unseres Schemas hinzu. Wählen Sie **Anfügen (Attach)** und auf dem nächsten Bildschirm die gleiche `BatchTutorial`-Datenquelle wie zu Beginn dieser Anleitung aus.

Fügen wir die folgende Zuweisungsvorlage für Anforderungen hinzu.

 **Zuweisungsvorlage für Anforderungen** 

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

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

Beachten Sie, dass wir die **BatchGetItem**Operation jetzt verwenden.

Unsere Zuweisungsvorlage für Antworten unterscheidet sich etwas, da wir uns für die Rückgabe einer `SensorReading`-Liste entschieden haben. Ordnen wir jetzt das Aufrufergebnis der gewünschten Form zu.

 **Zuweisungsvorlage für Antworten** 

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

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

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

$util.toJson($sensorReadings)
```

Speichern Sie den Resolver und navigieren Sie zur Seite „**Abfragen**“ der AWS AppSync Konsole. Rufen wir jetzt die Sensormesswerte ab\$1

Führen Sie die folgende Abfrage aus:

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

Wir haben erfolgreich die Verwendung von DynamoDB-Batchoperationen unter Verwendung von demonstriert. AWS AppSync

## Fehlerbehandlung
<a name="error-handling"></a>

In AWS AppSync Datenquellenoperationen können manchmal Teilergebnisse zurückgegeben werden. Wir verwenden den Begriff Teilergebnis, wenn bei der Ausgabe einer Operation einige Daten fehlen und darin ein Fehler enthalten ist. Da die Fehlerbehandlung grundsätzlich anwendungsspezifisch erfolgt, bietet Ihnen AWS AppSync die Möglichkeit, Fehler in der Zuweisungsvorlage für Antworten zu handhaben. Sollte beim Resolver ein Aufruffehler vorliegen, lässt sich dieser im Kontext an `$ctx.error` erkennen. Aufruffehler umfassen immer eine Nachricht und eine Art, auf die über die Eigenschaften `$ctx.error.message` und `$ctx.error.type`zugegriffen werden kann. Während die Zuweisungsvorlagen für Antworten aufgerufen werden, können Sie Teilergebnisse auf drei verschiedene Arten handhaben:

1. Übergehen des Aufruffehlers, indem nur Daten zurückgegeben werden

1. Melden des Fehlers (unter Verwendung von `$util.error(...)`), wodurch die Bewertung der Zuweisungsvorlage für Antworten unterbrochen wird und keine Daten zurückgegeben werden

1. Anfügen eines Fehler (unter Verwendung von `$util.appendError(...)`) und der gleichzeitigen Zurückgabe von Daten

Wir veranschaulichen jetzt jeden der drei oben genannten Punkte mit den DynamoDB-Stapelvorgängen.

### DynamoDB-Stapelvorgänge
<a name="dynamodb-batch-operations"></a>

Mit DynamoDB-Stapelvorgängen ist es möglich, dass ein Stapel teilweise abgeschlossen wird. Das bedeutet, dass einige der angeforderten Elemente oder Schlüssel nicht verarbeitet werden. Wenn AWS AppSync ein Stapel nicht abgeschlossen werden kann, werden unverarbeitete Elemente und ein Aufruffehler für den Kontext angezeigt.

Wir werden die Fehlerbehandlung mithilfe der `Query.getReadings`-Feldkonfiguration der `BatchGetItem`-Operation aus dem vorherigen Abschnitt dieser Anleitung implementieren. Dieses Mal nehmen wir jedoch an, dass bei der Ausführung des `Query.getReadings`-Felds die DynamoDB-Tabelle `temperatureReadings` den bereitgestellten Durchsatz überschritten hat. DynamoDB hat **ProvisionedThroughputExceededException**beim zweiten Versuch a ausgelöst, AWS AppSync um die verbleibenden Elemente im Stapel zu verarbeiten.

Der folgende JSON-Code stellt den serialisierten Kontext dar, nachdem der DynamoDB-Stapel aufgerufen, aber noch bevor die Zuweisungsvorlage für Antworten ausgewertet wurde.

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

Beachten Sie in diesem Kontext die folgenden Dinge:
+ der Aufruffehler wurde für den Kontext bei `$ctx.error` by festgelegt AWS AppSync, und der Fehlertyp wurde auf **DynamoDB**: gesetzt. ProvisionedThroughputExceededException
+ die Ergebnisse werden pro Tabelle unter `$ctx.result.data` zugeordnet, auch wenn ein Fehler vorhanden ist
+ unverarbeitete Schlüssel finden Sie unter `$ctx.result.data.unprocessedKeys`. Hier AWS AppSync konnte das Element mit dem Schlüssel (sensorId:1, timestamp:2018-02-01T 17:21:05.000 \$1 08:00) aufgrund des unzureichenden Tabellendurchsatzes nicht abgerufen werden.

 **Hinweis**: Für `BatchPutItem` gilt `$ctx.result.data.unprocessedItems`. Für `BatchDeleteItem` gilt `$ctx.result.data.unprocessedKeys`.

Sie können mit diesem Fehler auf drei verschiedene Arten umgehen.

#### 1. Übergehen des Aufruffehlers
<a name="swallowing-the-invocation-error"></a>

Wenn Daten ohne Verarbeitung des Aufruffehlers zurückgegeben werden, wird der Fehler effektiv übergangen. Auf diese Weise ist das Ergebnis für das angegebene GraphQL-Feld immer erfolgreich.

Die von uns geschriebene Zuweisungsvorlage für Antworten ist vertraut und konzentriert sich auf die Ergebnisdaten.

Zuweisungsvorlage für Antworten:

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

GraphQL-Antwort:

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

Der Fehlerantwort werden keine Fehler hinzugefügt, da nur auf Daten reagiert wird.

#### 2. Melden eines Fehlers, um die Vorlagenausführung abzubrechen
<a name="raising-an-error-to-abort-the-template-execution"></a>

Wenn Teilausfälle aus der Perspektive des Clients als vollständige Ausfälle behandelt werden sollten, können Sie die Ausführung der Vorlage abbrechen, um die Rückgabe von Daten zu verhindern. Das Dienstprogramm `$util.error(...)` erzielt genau dieses Verhalten.

Zuweisungsvorlage für Antworten:

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

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

GraphQL-Antwort:

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

Auch wenn der DynamoDB Stapelvorgang möglicherweise einige Ergebnisse zurückgegeben hat, haben wir uns entschieden, einen Fehler zu melden, indem das GraphQL-Feld `getReadings` mit Null angezeigt und der Fehler dem *Fehler*-Block der GraphQL-Antwort hinzugefügt wurde.

#### 3. Anfügen eines Fehlers bei der Rückgabe von Daten und Fehlern
<a name="appending-an-error-to-return-both-data-and-errors"></a>

In bestimmten Fällen können Anwendungen Teilergebnisse zurückgeben und die Clients über die unverarbeiteten Elemente benachrichtigen und so die Benutzererfahrung verbessern. Die Clients können entscheiden, eine Wiederholung zu implementieren oder den Fehler an den Endbenutzer zu übermitteln. Über das Dienstprogramm `$util.appendError(...)` kann der Anwendungs-Designer Fehler im Hinblick auf den Kontext anfügen, ohne dass sich dies auf die Bewertung der Vorlage auswirkt. Nach der Auswertung der Vorlage AWS AppSync werden alle Kontextfehler verarbeitet, indem sie an den Fehlerblock der GraphQL-Antwort angehängt werden.

Zuweisungsvorlage für Antworten:

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

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

Wir haben sowohl den Aufruffehler als auch das unprocessedKeys-Element an den Fehlerblock der GraphQL-Antwort weitergeleitet. Das `getReadings`-Feld gibt auch partielle Daten aus der **locationReadings**-Tabelle zurück, wie Sie in der nachstehenden Antwort sehen können.

GraphQL-Antwort:

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

# Durchführen von DynamoDB-Transaktionen in AWS AppSync
<a name="tutorial-dynamodb-transact"></a>

**Anmerkung**  
Wir unterstützen jetzt hauptsächlich die APPSYNC\$1JS-Laufzeit und ihre Dokumentation. [Bitte erwägen Sie, die APPSYNC\$1JS-Laufzeit und ihre Anleitungen hier zu verwenden.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

AWS AppSync unterstützt die Verwendung von Amazon DynamoDB-Transaktionsoperationen für eine oder mehrere Tabellen in einer einzigen Region. Zu den unterstützten Operationen gehören `TransactGetItems` und `TransactWriteItems`. Mithilfe dieser Funktionen können Sie Aufgaben wie die folgenden ausführen: AWS AppSync
+ Übermitteln einer Liste von Schlüsseln in einer einzigen Abfrage und Zurückgabe der Ergebnisse aus einer Tabelle
+ Lesen der Datensätze aus einer oder mehrerer Tabellen in einer einzigen Abfrage
+ Schreiben Sie Datensätze in einer Transaktion auf irgendeine all-or-nothing Weise in eine oder mehrere Tabellen
+ Ausführen von Transaktionen, wenn einige Bedingungen erfüllt sind

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

Wie bei anderen Resolvern müssen Sie eine Datenquelle in erstellen AWS AppSync und entweder eine Rolle erstellen oder eine vorhandene verwenden. Da Transaktionsvorgänge unterschiedliche Berechtigungen für DynamoDB-Tabellen erfordern, müssen Sie den konfigurierten Rollen Berechtigungen für Lese- oder Schreibaktionen gewähren:

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

------

 **Hinweis**: Rollen sind an Datenquellen in einer Datenquelle gebunden AWS AppSync, und Resolver für Felder werden für eine Datenquelle aufgerufen. Für Datenquellen, die für den Abruf von DynamoDB konfiguriert sind, ist nur eine Tabelle angegeben, um die Konfiguration zu vereinfachen. Möchten Sie jedoch einen Transaktionsvorgang an mehreren Tabellen mit nur einem Resolver ausführen, stellt dies eine erweiterte Aufgabe dar, und Sie müssen der Rolle dieser Datenquelle Zugriff auf alle Tabellen gewähren, mit denen der Resolver interagieren wird. Dies kann im Feld **Ressource (Resource)** in der IAM-Richtlinie weiter oben eingerichtet werden. Die Konfiguration der Tabellen, um Transaktionsaufrufe auszuführen, erfolgt in der Resolver-Vorlage und wird nachfolgend beschrieben.

## Datenquelle
<a name="data-source"></a>

Der Einfachheit halber verwenden wir die gleiche Datenquelle für alle in diesem Tutorial verwendeten Resolver. Erstellen Sie auf der Registerkarte **Datenquellen** eine neue DynamoDB-Datenquelle und geben Sie ihr einen Namen. **TransactTutorial** Sie können den Namen der Tabelle frei wählen, da Tabellennamen als Teil der Zuweisungsvorlage für Anforderungen bei Transaktionsvorgängen angegeben werden. Wir geben der Tabelle den Namen `empty`.

Wir haben zwei Tabellen mit den Bezeichnungen **savingAccounts** und **checkingAccounts**, beide mit `accountNumber` als Partitionsschlüssel, und eine **transactionHistory**-Tabelle mit `transactionId` als Partitionsschlüssel.

Für dieses Tutorial kann jede Rolle mit der folgenden eingebundenen Richtlinie verwendet werden: Ersetzen Sie `region` und `accountId` durch Ihre Region und Konto-ID:

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

------

## Transaktionen
<a name="transactions"></a>

Für dieses Beispiel ist der Kontext eine klassische Banktransaktion, bei der wir `TransactWriteItems` für folgende Aktionen verwenden:
+ Überweisen von Geld von Sparkonten auf Girokonten
+ Generieren neuer Transaktionsdatensätze für jede Transaktion

Anschließend verwenden wir `TransactGetItems`, um Details der Sparkonten und Girokonten abzurufen.

**Warnung**  
`TransactWriteItems`wird nicht unterstützt, wenn es zusammen mit Konflikterkennung und Konfliktlösung verwendet wird. Diese Einstellungen müssen deaktiviert werden, um mögliche Fehler zu vermeiden.

Wir definieren unser GraphQL-Schema wie folgt:

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

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

### TransactWriteItems - Konten auffüllen
<a name="transactwriteitems-populate-accounts"></a>

Um Geld zwischen Konten zu übertragen, müssen wir die Tabelle mit den Details füllen. Wir verwenden dazu die GraphQL-Operation `Mutation.populateAccounts`.

Klicken Sie im Abschnitt Schema neben dem `Mutation.populateAccounts` Vorgang auf **Anhängen**. Gehen Sie zu VTL Unit Resolvers und wählen Sie dann dieselbe `TransactTutorial` Datenquelle aus.

Verwenden Sie die folgende Zuweisungsvorlage für Anforderungen:

 **Zuweisungsvorlage für Anforderungen** 

```
#set($savingAccountTransactPutItems = [])
#set($index = 0)
#foreach($savingAccount in ${ctx.args.savingAccounts})
    #set($keyMap = {})
    $util.qr($keyMap.put("accountNumber", $util.dynamodb.toString($savingAccount.accountNumber)))
    #set($attributeValues = {})
    $util.qr($attributeValues.put("username", $util.dynamodb.toString($savingAccount.username)))
    $util.qr($attributeValues.put("balance", $util.dynamodb.toNumber($savingAccount.balance)))
    #set($index = $index + 1)
    #set($savingAccountTransactPutItem = {"table": "savingAccounts",
        "operation": "PutItem",
        "key": $keyMap,
        "attributeValues": $attributeValues})
    $util.qr($savingAccountTransactPutItems.add($savingAccountTransactPutItem))
#end

#set($checkingAccountTransactPutItems = [])
#set($index = 0)
#foreach($checkingAccount in ${ctx.args.checkingAccounts})
    #set($keyMap = {})
    $util.qr($keyMap.put("accountNumber", $util.dynamodb.toString($checkingAccount.accountNumber)))
    #set($attributeValues = {})
    $util.qr($attributeValues.put("username", $util.dynamodb.toString($checkingAccount.username)))
    $util.qr($attributeValues.put("balance", $util.dynamodb.toNumber($checkingAccount.balance)))
    #set($index = $index + 1)
    #set($checkingAccountTransactPutItem = {"table": "checkingAccounts",
        "operation": "PutItem",
        "key": $keyMap,
        "attributeValues": $attributeValues})
    $util.qr($checkingAccountTransactPutItems.add($checkingAccountTransactPutItem))
#end

#set($transactItems = [])
$util.qr($transactItems.addAll($savingAccountTransactPutItems))
$util.qr($transactItems.addAll($checkingAccountTransactPutItems))

{
    "version" : "2018-05-29",
    "operation" : "TransactWriteItems",
    "transactItems" : $util.toJson($transactItems)
}
```

Und die folgende Zuweisungsvorlage für Antworten:

 **Zuweisungsvorlage für Antworten** 

```
#if ($ctx.error)
    $util.appendError($ctx.error.message, $ctx.error.type, null, $ctx.result.cancellationReasons)
#end

#set($savingAccounts = [])
#foreach($index in [0..2])
    $util.qr($savingAccounts.add(${ctx.result.keys[$index]}))
#end

#set($checkingAccounts = [])
#foreach($index in [3..5])
    $util.qr($checkingAccounts.add(${ctx.result.keys[$index]}))
#end

#set($transactionResult = {})
$util.qr($transactionResult.put('savingAccounts', $savingAccounts))
$util.qr($transactionResult.put('checkingAccounts', $checkingAccounts))

$util.toJson($transactionResult)
```

Speichern Sie den Resolver und navigieren Sie zum Abschnitt **Abfragen** der AWS AppSync Konsole, um die Konten aufzufüllen.

Führen Sie die folgende Mutation aus:

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

Wir haben drei Sparkonten und drei Girokonten in einer Mutation gefüllt.

**Verwenden Sie die DynamoDB-Konsole, um zu überprüfen, ob Daten sowohl in den Tabellen **SavingAccounts als auch in checkingAccounts** angezeigt werden.**

### TransactWriteItems - Geld überweisen
<a name="transactwriteitems-transfer-money"></a>

Fügen Sie der `transferMoney`-Mutation mithilfe der folgenden **Zuweisungsvorlage für Anforderungen** einen Resolver an. Beachten Sie, dass die Werte von `amounts`, `savingAccountNumbers` und `checkingAccountNumbers` identisch sind.

```
#set($amounts = [])
#foreach($transaction in ${ctx.args.transactions})
    #set($attributeValueMap = {})
    $util.qr($attributeValueMap.put(":amount", $util.dynamodb.toNumber($transaction.amount)))
    $util.qr($amounts.add($attributeValueMap))
#end

#set($savingAccountTransactUpdateItems = [])
#set($index = 0)
#foreach($transaction in ${ctx.args.transactions})
    #set($keyMap = {})
    $util.qr($keyMap.put("accountNumber", $util.dynamodb.toString($transaction.savingAccountNumber)))
    #set($update = {})
    $util.qr($update.put("expression", "SET balance = balance - :amount"))
    $util.qr($update.put("expressionValues", $amounts[$index]))
    #set($index = $index + 1)
    #set($savingAccountTransactUpdateItem = {"table": "savingAccounts",
        "operation": "UpdateItem",
        "key": $keyMap,
        "update": $update})
    $util.qr($savingAccountTransactUpdateItems.add($savingAccountTransactUpdateItem))
#end

#set($checkingAccountTransactUpdateItems = [])
#set($index = 0)
#foreach($transaction in ${ctx.args.transactions})
    #set($keyMap = {})
    $util.qr($keyMap.put("accountNumber", $util.dynamodb.toString($transaction.checkingAccountNumber)))
    #set($update = {})
    $util.qr($update.put("expression", "SET balance = balance + :amount"))
    $util.qr($update.put("expressionValues", $amounts[$index]))
    #set($index = $index + 1)
    #set($checkingAccountTransactUpdateItem = {"table": "checkingAccounts",
        "operation": "UpdateItem",
        "key": $keyMap,
        "update": $update})
    $util.qr($checkingAccountTransactUpdateItems.add($checkingAccountTransactUpdateItem))
#end

#set($transactionHistoryTransactPutItems = [])
#foreach($transaction in ${ctx.args.transactions})
    #set($keyMap = {})
    $util.qr($keyMap.put("transactionId", $util.dynamodb.toString(${utils.autoId()})))
    #set($attributeValues = {})
    $util.qr($attributeValues.put("from", $util.dynamodb.toString($transaction.savingAccountNumber)))
    $util.qr($attributeValues.put("to", $util.dynamodb.toString($transaction.checkingAccountNumber)))
    $util.qr($attributeValues.put("amount", $util.dynamodb.toNumber($transaction.amount)))
    #set($transactionHistoryTransactPutItem = {"table": "transactionHistory",
        "operation": "PutItem",
        "key": $keyMap,
        "attributeValues": $attributeValues})
    $util.qr($transactionHistoryTransactPutItems.add($transactionHistoryTransactPutItem))
#end

#set($transactItems = [])
$util.qr($transactItems.addAll($savingAccountTransactUpdateItems))
$util.qr($transactItems.addAll($checkingAccountTransactUpdateItems))
$util.qr($transactItems.addAll($transactionHistoryTransactPutItems))

{
    "version" : "2018-05-29",
    "operation" : "TransactWriteItems",
    "transactItems" : $util.toJson($transactItems)
}
```

Wir werden drei Banktransaktionen in einem einzigen `TransactWriteItems`-Vorgang durchführen. Verwenden Sie die folgende **Vorlage für die Zuordnung von Antworten**:

```
#if ($ctx.error)
    $util.appendError($ctx.error.message, $ctx.error.type, null, $ctx.result.cancellationReasons)
#end

#set($savingAccounts = [])
#foreach($index in [0..2])
    $util.qr($savingAccounts.add(${ctx.result.keys[$index]}))
#end

#set($checkingAccounts = [])
#foreach($index in [3..5])
    $util.qr($checkingAccounts.add(${ctx.result.keys[$index]}))
#end

#set($transactionHistory = [])
#foreach($index in [6..8])
    $util.qr($transactionHistory.add(${ctx.result.keys[$index]}))
#end

#set($transactionResult = {})
$util.qr($transactionResult.put('savingAccounts', $savingAccounts))
$util.qr($transactionResult.put('checkingAccounts', $checkingAccounts))
$util.qr($transactionResult.put('transactionHistory', $transactionHistory))

$util.toJson($transactionResult)
```

Navigieren Sie nun zum Abschnitt **Queries (Abfragen)** der AWS AppSync -Konsole, und führen Sie die **transferMoney**-Mutation wie folgt aus:

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

Wir haben zwei Banktransaktionen in einer Mutation gesendet. **Verwenden Sie die DynamoDB-Konsole, um zu überprüfen, ob Daten in den Tabellen **SavingAccounts, **checkingAccounts**** und TransactionHistory angezeigt werden.**

### TransactGetItems - Konten abrufen
<a name="transactgetitems-retrieve-accounts"></a>

Um die Details aus dem Sparkonto und dem Girokonto in einer einzigen Transaktionsanforderung abzurufen, hängen wir einen Resolver an die `Query.getAccounts`-GraphQL-Operation in unserem Schema an. Wählen Sie **Anhängen**, gehen Sie zu VTL Unit Resolvers und wählen Sie dann auf dem nächsten Bildschirm dieselbe `TransactTutorial` Datenquelle aus, die Sie zu Beginn des Tutorials erstellt haben. Konfigurieren Sie die Vorlagen wie folgt:

 **Zuweisungsvorlage für Anforderungen** 

```
#set($savingAccountsTransactGets = [])
#foreach($savingAccountNumber in ${ctx.args.savingAccountNumbers})
    #set($savingAccountKey = {})
    $util.qr($savingAccountKey.put("accountNumber", $util.dynamodb.toString($savingAccountNumber)))
    #set($savingAccountTransactGet = {"table": "savingAccounts", "key": $savingAccountKey})
    $util.qr($savingAccountsTransactGets.add($savingAccountTransactGet))
#end

#set($checkingAccountsTransactGets = [])
#foreach($checkingAccountNumber in ${ctx.args.checkingAccountNumbers})
    #set($checkingAccountKey = {})
    $util.qr($checkingAccountKey.put("accountNumber", $util.dynamodb.toString($checkingAccountNumber)))
    #set($checkingAccountTransactGet = {"table": "checkingAccounts", "key": $checkingAccountKey})
    $util.qr($checkingAccountsTransactGets.add($checkingAccountTransactGet))
#end

#set($transactItems = [])
$util.qr($transactItems.addAll($savingAccountsTransactGets))
$util.qr($transactItems.addAll($checkingAccountsTransactGets))

{
    "version" : "2018-05-29",
    "operation" : "TransactGetItems",
    "transactItems" : $util.toJson($transactItems)
}
```

 **Zuweisungsvorlage für Antworten** 

```
#if ($ctx.error)
    $util.appendError($ctx.error.message, $ctx.error.type, null, $ctx.result.cancellationReasons)
#end

#set($savingAccounts = [])
#foreach($index in [0..2])
    $util.qr($savingAccounts.add(${ctx.result.items[$index]}))
#end

#set($checkingAccounts = [])
#foreach($index in [3..4])
    $util.qr($checkingAccounts.add($ctx.result.items[$index]))
#end

#set($transactionResult = {})
$util.qr($transactionResult.put('savingAccounts', $savingAccounts))
$util.qr($transactionResult.put('checkingAccounts', $checkingAccounts))

$util.toJson($transactionResult)
```

Speichern Sie den Resolver und navigieren Sie zu den **Query-Abschnitten** der Konsole. AWS AppSync Um die Sparkonten und die Girokonten abzurufen, führen Sie die folgende Abfrage aus:

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

Wir haben erfolgreich die Verwendung von DynamoDB-Transaktionen unter Verwendung von demonstriert. AWS AppSync

# Verwendung von HTTP-Resolvern in AWS AppSync
<a name="tutorial-http-resolvers"></a>

**Anmerkung**  
Wir unterstützen jetzt hauptsächlich die APPSYNC\$1JS-Laufzeit und ihre Dokumentation. [Bitte erwägen Sie, die APPSYNC\$1JS-Laufzeit und ihre Anleitungen hier zu verwenden.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

AWS AppSync ermöglicht es Ihnen, unterstützte Datenquellen (d. h. Amazon DynamoDB AWS Lambda, Amazon OpenSearch Service oder Amazon Aurora) zu verwenden, um verschiedene Operationen durchzuführen, zusätzlich zu beliebigen HTTP-Endpunkten zur Auflösung von GraphQL-Feldern. Sobald die HTTP-Endpunkte verfügbar sind, können Sie sie mit einer Datenquelle verbinden. Anschließend können Sie einen Resolver im Schema konfigurieren, um GraphQL-Operationen wie Abfragen, Mutationen und Abonnements auszuführen. Dieses Tutorial führt Sie durch einige häufig auftretende Beispiele.

In diesem Tutorial verwenden Sie eine REST-API (erstellt mit Amazon API Gateway und Lambda) mit einem AWS AppSync GraphQL-Endpunkt.

## One-Click-Setup
<a name="one-click-setup"></a>

Wenn Sie automatisch einen GraphQL-Endpunkt AWS AppSync mit einem konfigurierten HTTP-Endpunkt einrichten möchten (mit Amazon API Gateway und Lambda), können Sie die folgende AWS CloudFormation Vorlage verwenden:

[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-full.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-full.yaml)

## Erstellen einer REST-API
<a name="creating-a-rest-api"></a>

Sie können die folgende AWS CloudFormation Vorlage verwenden, um einen REST-Endpunkt einzurichten, der für dieses Tutorial funktioniert:

[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)

Der AWS CloudFormation Stack führt die folgenden Schritte aus:

1. Richtet eine Lambda-Funktion ein, die die Geschäftslogik für den Mikroservice enthält.

1. Richtet eine API-Gateway-REST-API mit der folgenden endpoint/method/content Typkombination ein:


****  

| API-Ressourcenpfad | HTTP-Methode | Unterstützter Inhaltstyp | 
| --- | --- | --- | 
|  /v1/users  |  POST  |  application/json  | 
|  /v1/users  |  GET  |  application/json  | 
|  /v1/users/1  |  GET  |  application/json  | 
|  /v1/users/1  |  PUT  |  application/json  | 
|  /v1/users/1  |  DELETE  |  application/json  | 

## Erstellen der GraphQL-API
<a name="creating-your-graphql-api"></a>

Um die GraphQL-API zu erstellen in AWS AppSync:
+ Öffnen Sie die AWS AppSync Konsole und wählen Sie **Create API**.
+ Geben Sie für den API-Namen `UserData` ein.
+ Wählen Sie **Custom schema (Benutzerdefiniertes Schema)**.
+ Wählen Sie **Erstellen** aus.

Die AWS AppSync Konsole erstellt mithilfe des API-Schlüsselauthentifizierungsmodus eine neue GraphQL-API für Sie. Sie können in der Konsole den Rest der GraphQL-API einrichten und im weiteren Verlauf dieses Tutorials abfragen.

## Erstellen eines GraphQL-Schemas
<a name="creating-a-graphql-schema"></a>

Da wir jetzt eine GraphQL-API haben, erstellen Sie ein GraphQL-Schema. Stellen Sie im Schema-Editor in der AWS AppSync Konsole sicher, dass Ihr Schema dem folgenden Schema entspricht:

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

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

## Konfigurieren der HTTP-Datenquelle
<a name="configure-your-http-data-source"></a>

Gehen Sie wie folgt vor, um die HTTP-Datenquelle zu konfigurieren:
+ Wählen Sie auf der **DataSources**Registerkarte **Neu** aus, und geben Sie dann einen benutzerfreundlichen Namen für die Datenquelle ein (z. B.`HTTP`).
+ Wählen Sie für **Data source type (Datenquellentyp)** die Option **HTTP** aus.
+ Legen Sie den Endpunkt auf den erstellten API-Gateway-Endpunkt fest. Stellen Sie sicher, dass Sie den Namen der Stufe nicht in den Namen des Endpunkts einschließen.

 **Hinweis:** Derzeit werden nur öffentliche Endpunkte von AWS AppSync unterstützt.

 **Hinweis:** Weitere Informationen zu den Zertifizierungsstellen, die vom AWS AppSync Dienst anerkannt werden, finden Sie unter [Zertifizierungsstellen (CA) Recognized by AWS AppSync for HTTPS Endpoints](http-cert-authorities.md#aws-appsync-http-certificate-authorities).

## Konfigurieren von Resolvern
<a name="configuring-resolvers"></a>

In diesem Schritt verbinden Sie die HTTP-Datenquelle mit der Abfrage **getUser**.

Richten Sie den Resolver wie folgt ein:
+ Wählen Sie die Registerkarte **Schema** aus.
+ Suchen Sie im Bereich **Data types (Datentypen)** rechts unter dem **Query type (Abfragetyp)** das Feld **getUser** und wählen Sie **Attach(Anfügen)** aus.
+ Wählen Sie für **Data source name (Datenquellenname)** die Option **HTTP** aus.
+ Fügen Sie unter **Configure the request mapping template (Zuweisungsvorlage für Anforderungen konfigurieren)** den folgenden Code ein:

```
{
    "version": "2018-05-29",
    "method": "GET",
    "params": {
        "headers": {
            "Content-Type": "application/json"
        }
    },
    "resourcePath": $util.toJson("/v1/users/${ctx.args.id}")
}
```
+ Fügen Sie unter **Configure the response mapping template (Zuweisungsvorlage für Antworten konfigurieren)** den folgenden Code ein:

```
## return the body
#if($ctx.result.statusCode == 200)
    ##if response is 200
    $ctx.result.body
#else
    ##if response is not 200, append the response to error block.
    $utils.appendError($ctx.result.body, "$ctx.result.statusCode")
#end
```
+ Wählen Sie auf der Registerkarte **Query (Abfrage)** und führen Sie dann folgende Abfrage aus:

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

Folgende Antwort sollte zurückgegeben werden:

```
{
    "data": {
        "getUser": {
            "id": "1",
            "username": "nadia"
        }
    }
}
```
+ Wählen Sie die Registerkarte **Schema** aus.
+ Suchen Sie im Bereich **Data types (Datentypen)** rechts unter **Mutation** das Feld **addUser** und wählen Sie **Attach (Anfügen)** aus.
+ Wählen Sie für **Data source name (Datenquellenname)** die Option **HTTP** aus.
+ Fügen Sie unter **Configure the request mapping template (Zuweisungsvorlage für Anforderungen konfigurieren)** den folgenden Code ein:

```
{
    "version": "2018-05-29",
    "method": "POST",
    "resourcePath": "/v1/users",
    "params":{
      "headers":{
        "Content-Type": "application/json",
      },
      "body": $util.toJson($ctx.args.userInput)
    }
}
```
+ Fügen Sie unter **Configure the response mapping template (Zuweisungsvorlage für Antworten konfigurieren)** den folgenden Code ein:

```
## Raise a GraphQL field error in case of a datasource invocation error
#if($ctx.error)
    $util.error($ctx.error.message, $ctx.error.type)
#end
## if the response status code is not 200, then return an error. Else return the body **
#if($ctx.result.statusCode == 200)
    ## If response is 200, return the body.
    $ctx.result.body
#else
    ## If response is not 200, append the response to error block.
    $utils.appendError($ctx.result.body, "$ctx.result.statusCode")
#end
```
+ Wählen Sie auf der Registerkarte **Query (Abfrage)** und führen Sie dann folgende Abfrage aus:

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

Folgende Antwort sollte zurückgegeben werden:

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

## Dienste aufrufen AWS
<a name="invoking-aws-services"></a>

Sie können HTTP-Resolver verwenden, um eine GraphQL-API-Schnittstelle für AWS Dienste einzurichten. HTTP-Anfragen an AWS müssen mit dem [Signature Version 4-Prozess](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html) signiert werden, damit identifiziert werden AWS kann, wer sie gesendet hat. AWS AppSync berechnet die Signatur in Ihrem Namen, wenn Sie der HTTP-Datenquelle eine IAM-Rolle zuordnen.

Sie stellen zwei zusätzliche Komponenten bereit, um AWS Dienste mit HTTP-Resolvern aufzurufen:
+ Eine IAM-Rolle mit Berechtigungen zum Aufrufen des Dienstes AWS APIs
+ Signierkonfiguration in der Datenquelle

Wenn Sie den [ListGraphqlApis Vorgang](https://docs.aws.amazon.com/appsync/latest/APIReference/API_ListGraphqlApis.html) beispielsweise mit HTTP-Resolvern aufrufen möchten, [erstellen Sie zunächst eine IAM-Rolle](attaching-a-data-source.md#aws-appsync-getting-started-build-a-schema-from-scratch), der die folgende AWS AppSync Richtlinie zugewiesen ist:

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

****  

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

------

Als Nächstes erstellen Sie die HTTP-Datenquelle für. AWS AppSync In diesem Beispiel rufen Sie AWS AppSync in der Region USA West (Oregon) auf. Richten Sie die folgende HTTP-Konfiguration in einer Datei mit dem Namen `http.json` ein, die die Signierregion und den Servicenamen enthält:

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

Verwenden Sie dann die, AWS CLI um die Datenquelle mit einer zugehörigen Rolle wie folgt zu erstellen:

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

Wenn Sie einen Resolver an das Feld im Schema anhängen, verwenden Sie zum Aufrufen AWS AppSync die folgende Vorlage für die Anforderungszuweisung:

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

Wenn Sie eine GraphQL-Abfrage für diese Datenquelle ausführen, AWS AppSync signiert die Anfrage mit der von Ihnen angegebenen Rolle und fügt die Signatur in die Anfrage ein. Die Abfrage gibt eine Liste von AWS AppSync GraphQL APIs in Ihrem Konto in dieser AWS Region zurück.

# Verwenden von Aurora Serverless v2 mit AWS AppSync
<a name="tutorial-rds-resolvers"></a>

Connect Ihre GraphQL-API mit Aurora Serverless-Datenbanken mithilfe von. AWS AppSync Mit dieser Integration können Sie SQL-Anweisungen über GraphQL-Abfragen, -Mutationen und -Subskriptionen ausführen und so flexibel mit Ihren relationalen Daten interagieren.

**Anmerkung**  
Für dieses Tutorial wird die Region `US-EAST-1` verwendet.

**Vorteile**
+ Nahtlose Integration zwischen GraphQL und relationalen Datenbanken
+ Fähigkeit, SQL-Operationen über GraphQL-Schnittstellen durchzuführen
+ Serverlose Skalierbarkeit mit Aurora Serverless v2
+ Sicherer Datenzugriff über AWS Secrets Manager
+ Schutz vor SQL-Injection durch Eingabebereinigung
+ Flexible Abfragefunktionen, einschließlich Filter- und Bereichsoperationen

**Häufige Anwendungsfälle**
+ Entwicklung skalierbarer Anwendungen mit relationalen Datenanforderungen
+ Um APIs diese zu erstellen, sind sowohl GraphQL-Flexibilität als auch SQL-Datenbankfunktionen erforderlich
+ Verwaltung von Datenoperationen durch GraphQL-Mutationen und Abfragen
+ Implementierung sicherer Datenbankzugriffsmuster

In diesem Tutorial lernen Sie Folgendes.
+ Richten Sie einen Aurora Serverless v2-Cluster ein
+ Aktivieren Sie die Daten-API-Funktionalität
+ Datenbankstrukturen erstellen und konfigurieren
+ Definieren Sie GraphQL-Schemas für Datenbankoperationen
+ Implementieren Sie Resolver für Abfragen und Mutationen
+ Schützen Sie Ihren Datenzugriff durch eine angemessene Eingabebereinigung
+ Führen Sie verschiedene Datenbankoperationen über GraphQL-Schnittstellen aus

**Topics**
+ [Richten Sie Ihren Datenbankcluster ein](#create-cluster)
+ [Aktivieren der Daten-API](#enable-data-api)
+ [Datenbank und Tabelle erstellen](#create-database-and-table)
+ [GraphQL-Schema](#graphql-schema)
+ [Connect Sie Ihre API mit Datenbankoperationen](#configuring-resolvers)
+ [Ändern Sie Ihre Daten über die API](#run-mutations)
+ [Rufen Sie Ihre Daten ab](#run-queries)
+ [Schützen Sie Ihren Datenzugriff](#input-sanitization)

## Richten Sie Ihren Datenbankcluster ein
<a name="create-cluster"></a>

Bevor Sie eine Amazon RDS-Datenquelle hinzufügen AWS AppSync, müssen Sie zunächst eine Daten-API auf einem Aurora Serverless v2-Cluster aktivieren und **einen geheimen Schlüssel mithilfe von *AWS Secrets Manager*konfigurieren**. Sie können einen Aurora Serverless v2-Cluster erstellen, indem Sie: AWS CLI

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

Dadurch wird ein ARN für den Cluster zurückgegeben.

Nachdem Sie den Cluster erstellt haben, müssen Sie mit dem folgenden Befehl eine Aurora Serverless v2-Instance hinzufügen.

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

**Anmerkung**  
Die Aktivierung dieser Endpunkte benötigt Zeit. Sie können ihren Status in der Amazon RDS-Konsole auf der Registerkarte **Konnektivität und Sicherheit** für den Cluster überprüfen. Sie können den Status Ihres Clusters auch mit dem folgenden AWS CLI Befehl überprüfen.   

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

Sie können ein *Secret* mithilfe der AWS Secrets Manager Konsole oder AWS CLI mit einer Eingabedatei wie der folgenden erstellen, indem Sie die `USERNAME` und `COMPLEX_PASSWORD` aus dem vorherigen Schritt verwenden.

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

Übergeben Sie dies als Parameter an AWS CLI:

```
aws secretsmanager create-secret --name HttpRDSSecret --secret-string file://creds.json --region us-east-1
```

Dadurch wird ein ARN für das Secret zurückgegeben.

 **Notieren Sie sich den ARN** Ihres Aurora Serverless Clusters und Secret für die spätere Verwendung in der AppSync Konsole, wenn Sie eine Datenquelle erstellen.

## Aktivieren der Daten-API
<a name="enable-data-api"></a>

Die Daten-API können Sie auf Ihrem Cluster aktivieren, indem Sie die [folgende Anleitung aus der RDS-Dokumentation](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/data-api.html) ausführen. Die Daten-API muss aktiviert werden, bevor sie als AppSync Datenquelle hinzugefügt werden kann.

## Datenbank und Tabelle erstellen
<a name="create-database-and-table"></a>

Sobald Sie Ihre Daten-API aktiviert haben, können Sie sicherstellen, dass sie mit dem `aws rds-data execute-statement` Befehl in der funktioniert AWS CLI. Dadurch wird sichergestellt, dass Ihr Aurora Serverless-Cluster korrekt konfiguriert ist, bevor Sie ihn zu Ihrer AppSync API hinzufügen. Erstellen Sie zunächst eine Datenbank namens *TESTDB* mit dem folgenden `--sql` Parameter:

```
aws rds-data execute-statement --resource-arn "arn:aws:rds:us-east-1:123456789000:cluster:http-endpoint-test" \
--schema "mysql"  --secret-arn "arn:aws:secretsmanager:us-east-1:123456789000:secret:testHttp2-AmNvc1"  \
--region us-east-1 --sql "create DATABASE TESTDB"
```

Wenn dies fehlerfrei ausgeführt wird, fügen Sie mit dem Befehl *create table* eine Tabelle hinzu:

```
aws rds-data execute-statement --resource-arn "arn:aws:rds:us-east-1:123456789000:cluster:http-endpoint-test" \
 --schema "mysql"  --secret-arn "arn:aws:secretsmanager:us-east-1:123456789000:secret:testHttp2-AmNvc1" \
 --region us-east-1 \
 --sql "create table Pets(id varchar(200), type varchar(200), price float)" --database "TESTDB"
```

Wenn alles ohne Probleme gelaufen ist, können Sie den Cluster als Datenquelle zu Ihrer AppSync API hinzufügen.

## GraphQL-Schema
<a name="graphql-schema"></a>

Ihre Aurora Serverless-Daten-API ist eingerichtet und wird mit einer Tabelle ausgeführt. Jetzt erstellen wir ein GraphQL-Schema und fügen Resolver an, um Mutationen und Abonnements durchzuführen. Erstellen Sie eine neue API in der AWS AppSync Konsole, navigieren Sie zur **Schemaseite** und geben Sie Folgendes ein:

```
type Mutation {
    createPet(input: CreatePetInput!): Pet
    updatePet(input: UpdatePetInput!): Pet
    deletePet(input: DeletePetInput!): Pet
}

input CreatePetInput {
    type: PetType
    price: Float!
}

input UpdatePetInput {
id: ID!
    type: PetType
    price: Float!
}

input DeletePetInput {
    id: ID!
}

type Pet {
    id: ID!
    type: PetType
    price: Float
}

enum PetType {
    dog
    cat
    fish
    bird
    gecko
}

type Query {
    getPet(id: ID!): Pet
    listPets: [Pet]
    listPetsByPriceRange(min: Float, max: Float): [Pet]
}

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

 **Speichern** Sie Ihr Schema. Navigieren Sie zur Seite **Data Sources (Datenquellen)** und erstellen Sie eine neue Datenquelle. Wählen Sie für den Typ der Datenquelle **Relationale Datenbank** aus und geben Sie einen aussagekräftigen Namen ein. Verwenden Sie den im letzten Schritt erstellten Datenbanknamen und den darin erstellen **Cluster ARN (Cluster-ARN)**. Für die **Rolle** können Sie entweder eine neue Rolle AppSync erstellen lassen oder eine mit einer Richtlinie erstellen, die der folgenden ähnelt:

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

****  

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

------

Beachten Sie, dass diese Richtlinie zwei **Anweisungen** enthält, die den Zugriff der Rolle gewähren. Die erste **Ressource** ist Ihr Aurora Serverless-Cluster und die zweite ist Ihr AWS Secrets Manager ARN. Sie müssen **BEIDE** ARNs in der AppSync Datenquellenkonfiguration angeben, bevor Sie auf **Erstellen** klicken.

Übergeben Sie dies als Parameter an den AWS CLI.

```
aws secretsmanager create-secret \
  --name HttpRDSSecret \
  --secret-string file://creds.json \
  --region us-east-1
```

Dadurch wird ein ARN für das Secret zurückgegeben. Notieren Sie sich den ARN Ihres Aurora Serverless Clusters und Secret für später, wenn Sie eine Datenquelle in der AWS AppSync Konsole erstellen.

### Erstellen Sie Ihre Datenbankstruktur
<a name="create-database-and-table"></a>

Sobald Sie Ihre Daten-API aktiviert haben, können Sie sicherstellen, dass sie mit dem `aws rds-data execute-statement` Befehl in der funktioniert AWS CLI. Dadurch wird sichergestellt, dass Ihr Aurora Serverless v2-Cluster korrekt konfiguriert ist, bevor Sie ihn zu Ihrer AWS AppSync API hinzufügen. Erstellen Sie zunächst eine Datenbank namens *TESTDB* mit dem folgenden `--sql` Parameter.

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

Wenn dies ohne Fehler läuft, fügen Sie mit dem folgenden Befehl *create table eine Tabelle* hinzu.

```
aws rds-data execute-statement \
      --resource-arn "arn:aws:rds:us-east-1:111122223333:cluster:http-endpoint-test" \
      --secret-arn "arn:aws:secretsmanager:us-east-1:111122223333:secret:testHttp2-AmNvc1" \
      --region us-east-1 \
      --sql "create table Pets(id varchar(200), type varchar(200), price float)" \
      --database "TESTDB"
```

### Entwerfen Sie Ihre API-Schnittstelle
<a name="graphql-schema"></a>

Nachdem die Aurora Serverless v2 Data API mit einer Tabelle betriebsbereit ist, erstellen Sie ein GraphQL-Schema und hängen Sie Resolver an, um Mutationen und Abonnements durchzuführen. Erstellen Sie eine neue API in der AWS AppSync Konsole, navigieren Sie zur **Schemaseite** in der Konsole und geben Sie Folgendes ein.

```
type Mutation {
        createPet(input: CreatePetInput!): Pet
        updatePet(input: UpdatePetInput!): Pet
        deletePet(input: DeletePetInput!): Pet
    }
    
    input CreatePetInput {
        type: PetType
        price: Float!
    }
    
    input UpdatePetInput {
        id: ID!
        type: PetType
        price: Float!
    }
    
    input DeletePetInput {
        id: ID!
    }
    
    type Pet {
        id: ID!
        type: PetType
        price: Float
    }
    
    enum PetType {
        dog
        cat
        fish
        bird
        gecko
    }
    
    type Query {
        getPet(id: ID!): Pet
        listPets: [Pet]
        listPetsByPriceRange(min: Float, max: Float): [Pet]
    }
    
    schema {
        query: Query
        mutation: Mutation
    }
```

 **Speichern** Sie Ihr Schema. Navigieren Sie zur Seite **Data Sources (Datenquellen)** und erstellen Sie eine neue Datenquelle. Wählen Sie **Relationale Datenbank** als **Datenquellentyp** und geben Sie einen benutzerfreundlichen Namen ein. Verwenden Sie den im letzten Schritt erstellten Datenbanknamen und den darin erstellen **Cluster ARN (Cluster-ARN)**. Für die **Rolle** können Sie entweder eine neue Rolle AWS AppSync erstellen lassen oder eine mit einer Richtlinie erstellen, die der folgenden ähnelt.

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

****  

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

------

Beachten Sie, dass diese Richtlinie zwei **Anweisungen** enthält, die den Zugriff der Rolle gewähren. Die erste **Ressource** ist Ihr Aurora Serverless v2-Cluster und die zweite ist Ihr AWS Secrets Manager ARN. Sie müssen **BEIDE** ARNs in der AWS AppSync Datenquellenkonfiguration angeben, bevor Sie auf **Erstellen** klicken.

## Connect Sie Ihre API mit Datenbankoperationen
<a name="configuring-resolvers"></a>

Da wir nun ein gültiges GraphQL-Schema und eine RDS-Datenquelle haben, können Sie Resolver an die GraphQL-Felder Ihres Schemas anhängen. Unsere API bietet folgende Funktionen:

1. *erstellen Sie mit dem Feld Mutation.createPet ein Haustier*

1. *aktualisieren Sie ein Haustier mithilfe des Felds Mutation.UpdatePet*

1. *lösche ein Haustier mithilfe des Felds Mutation.deletePet*

1. *Holen Sie sich eine Single mithilfe des Felds Query.getPet*

1. *listet alle mithilfe des Felds query.listPets auf*

1. *listet mithilfe der Abfrage Haustiere in einer Preisklasse auf. listPetsByPriceRange*Feld

### Mutation.createPet
<a name="mutation-createpet"></a>

Wählen Sie im Schema-Editor in der AWS AppSync Konsole auf der rechten Seite **Attach Resolver** for `createPet(input: CreatePetInput!): Pet` aus. Wählen Sie Ihre RDS-Datenquelle aus. Fügen Sie die folgende Vorlage im Abschnitt **request mapping template (Zuweisungsvorlage für Anforderungen)** ein:

```
#set($id=$utils.autoId())
{
"version": "2018-05-29",
    "statements": [
        "insert into Pets VALUES (:ID, :TYPE, :PRICE)",
        "select * from Pets WHERE id = :ID"
    ],
    "variableMap": {
        ":ID": "$ctx.args.input.id",
        ":TYPE": $util.toJson($ctx.args.input.type),
        ":PRICE": $util.toJson($ctx.args.input.price)
    }
}
```

**Das System führt SQL-Anweisungen sequentiell aus, basierend auf der Reihenfolge im Anweisungsarray.** Die Ergebnisse werden wieder in derselben Reihenfolge zurückgegeben. Da es sich um eine Mutation handelt, führen Sie nach dem *Einfügen* eine *SELECT-Anweisung aus*, um die festgeschriebenen Werte abzurufen und die GraphQL-Antwortzuordnungsvorlage zu füllen.

Fügen Sie die folgende Vorlage im Abschnitt **response mapping template (Zuweisungsvorlage für Antworten)** ein:

```
$utils.toJson($utils.rds.toJsonObject($ctx.result)[1][0])
```

Da die *Anweisungen* zwei SQL-Abfragen enthalten, müssen wir das zweite Ergebnis in der Matrix, die aus der Datenbank zurückgegeben wird, wie folgt angeben: `$utils.rds.toJsonString($ctx.result))[1][0])`.

### Mutation.updatePet
<a name="mutation-updatepet"></a>

Wählen Sie im Schema-Editor in der AWS AppSync Konsole **Attach Resolver for** aus. `updatePet(input: UpdatePetInput!): Pet` Wählen Sie Ihre **RDS-Datenquelle aus**. Fügen **Sie im Abschnitt Vorlage für die Anforderungszuweisung** die folgende Vorlage hinzu.

```
{
"version": "2018-05-29",
    "statements": [
        $util.toJson("update Pets set type=:TYPE, price=:PRICE WHERE id=:ID"),
        $util.toJson("select * from Pets WHERE id = :ID")
    ],
    "variableMap": {
        ":ID": "$ctx.args.input.id",
        ":TYPE": $util.toJson($ctx.args.input.type),
        ":PRICE": $util.toJson($ctx.args.input.price)
    }
}
```

Fügen Sie im Abschnitt **Vorlage für die Antwortzuordnung** die folgende Vorlage hinzu.

```
$utils.toJson($utils.rds.toJsonObject($ctx.result)[1][0])
```

### Mutation.deletePet
<a name="mutation-deletepet"></a>

Wählen Sie im Schema-Editor in der AWS AppSync Konsole **Attach Resolver** for `deletePet(input: DeletePetInput!): Pet` aus. Wählen Sie Ihre **RDS-Datenquelle aus**. Fügen **Sie im Abschnitt Vorlage für die Anforderungszuweisung** die folgende Vorlage hinzu.

```
{
"version": "2018-05-29",
    "statements": [
        $util.toJson("select * from Pets WHERE id=:ID"),
        $util.toJson("delete from Pets WHERE id=:ID")
    ],
    "variableMap": {
        ":ID": "$ctx.args.input.id"
    }
}
```

Fügen Sie im Abschnitt **Vorlage für die Antwortzuordnung** die folgende Vorlage hinzu.

```
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0][0])
```

### Query.getPet
<a name="query-getpet"></a>

Nachdem die Mutationen für Ihr Schema erstellt wurden, können Sie die drei Abfragen miteinander verbinden, um zu zeigen, wie Sie einzelne Elemente und Listen abrufen und SQL-Filter anwenden können. Wählen Sie im **Schema-Editor** in der AWS AppSync Konsole **Attach Resolver** for `getPet(id: ID!): Pet` aus. Wählen Sie Ihre **RDS-Datenquelle aus**. Fügen **Sie im Abschnitt Vorlage für die Anforderungszuweisung** die folgende Vorlage hinzu.

```
{
"version": "2018-05-29",
        "statements": [
            $util.toJson("select * from Pets WHERE id=:ID")
    ],
    "variableMap": {
        ":ID": "$ctx.args.id"
    }
}
```

Fügen Sie die folgende Vorlage im Abschnitt **response mapping template (Zuweisungsvorlage für Antworten)** ein:

```
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0][0])
```

### Query.listPets
<a name="query-listpets"></a>

Wählen Sie im Schema-Editor in der AWS AppSync Konsole auf der rechten Seite **Attach Resolver** for `getPet(id: ID!): Pet` aus. Wählen Sie Ihre **RDS-Datenquelle aus**. Fügen **Sie im Abschnitt Vorlage für die Anforderungszuweisung** die folgende Vorlage hinzu.

```
{
    "version": "2018-05-29",
    "statements": [
        "select * from Pets"
    ]
}
```

Fügen Sie im Abschnitt **Vorlage für die Antwortzuordnung** die folgende Vorlage hinzu.

```
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])
```

### Abfrage. listPetsByPriceRange
<a name="query-listpetsbypricerange"></a>

Wählen Sie im Schema-Editor in der AWS AppSync Konsole auf der rechten Seite **Attach Resolver** for `getPet(id: ID!): Pet` aus. Wählen Sie Ihre **RDS-Datenquelle aus**. Fügen **Sie im Abschnitt Vorlage für die Anforderungszuweisung** die folgende Vorlage hinzu.

```
{
    "version": "2018-05-29",
    "statements": [
            "select * from Pets where price > :MIN and price < :MAX"
    ],

    "variableMap": {
        ":MAX": $util.toJson($ctx.args.max),
        ":MIN": $util.toJson($ctx.args.min)
    }
}
```

Fügen Sie die folgende Vorlage im Abschnitt **response mapping template (Zuweisungsvorlage für Antworten)** ein:

```
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])
```

## Ändern Sie Ihre Daten über die API
<a name="run-mutations"></a>

Nachdem Sie nun alle Resolver mit SQL-Anweisungen konfiguriert und Ihre GraphQL-API Ihrer Aurora Serverless-Daten-API zugewiesen haben, können Sie damit beginnen, Mutationen und Abfragen durchzuführen. Wählen Sie in der AWS AppSync Konsole den Tab **Abfragen** und geben Sie Folgendes ein, um ein Haustier zu erstellen:

```
mutation add {
    createPet(input : { type:fish, price:10.0 }){
        id
        type
        price
    }
}
```

Die Antwort enthält die *ID*, den *Typ* und den *Preis*. Beispiel:

```
{
  "data": {
    "createPet": {
      "id": "c6fedbbe-57ad-4da3-860a-ffe8d039882a",
      "type": "fish",
      "price": "10.0"
    }
  }
}
```

Sie können dieses Element verändern, indem Sie die Mutation *updatePet* ausführen:

```
mutation update {
    updatePet(input : {
        id: ID_PLACEHOLDER,
        type:bird,
        price:50.0
    }){
        id
        type
        price
    }
}
```

Beachten Sie, dass wir die *id* verwendet haben, die von der vorherigen *createPet*-Operation zurückgegeben wurde. Dies ist ein eindeutiger Wert für Ihren Datensatz, da der Resolver `$util.autoId()` verwendet hat. Auf ähnliche Weise können Sie einen Datensatz löschen:

```
mutation delete {
    deletePet(input : {id:ID_PLACEHOLDER}){
        id
        type
        price
    }
}
```

Erstellen Sie mit der ersten Mutation einige Datensätze mit unterschiedlichen Werten für *price* und führen Sie dann einige Abfragen aus.

## Rufen Sie Ihre Daten ab
<a name="run-queries"></a>

Verwenden Sie weiterhin auf der Registerkarte **Abfragen** der Konsole die folgende Anweisung, um alle von Ihnen erstellten Datensätze aufzulisten.

```
query allpets {
    listPets {
        id
        type
        price
    }
}
```

Nutzen Sie das SQL *WHERE-Prädikat*, das `where price > :MIN and price < :MAX` in unserer Zuordnungsvorlage für *Query enthalten war. listPetsByPriceRange*mit der folgenden GraphQL-Abfrage:

```
query petsByPriceRange {
    listPetsByPriceRange(min:1, max:11) {
        id
        type
        price
    }
}
```

Es werden nur Datensätze mit einem *Preis* über 1 \$1 und unter 10 \$1 angezeigt. Abschließend können Sie wie folgt Abfragen ausführen, um einzelne Datensätze abzurufen:

```
query onePet {
    getPet(id:ID_PLACEHOLDER){
        id
        type
        price
    }
}
```

## Schützen Sie Ihren Datenzugriff
<a name="input-sanitization"></a>

SQL Injection ist eine Sicherheitslücke in Datenbankanwendungen. Sie tritt auf, wenn Angreifer bösartigen SQL-Code über Benutzereingabefelder einfügen. Dies kann unbefugten Zugriff auf Datenbankdaten ermöglichen. Wir empfehlen Ihnen, alle Benutzereingaben vor der Verarbeitung sorgfältig zu überprüfen und zu bereinigen, um sich vor SQL-Injection-Angriffen zu schützen. `variableMap` Wenn Variablenzuordnungen nicht verwendet werden, sind Sie dafür verantwortlich, die Argumente ihrer GraphQL-Operationen zu bereinigen. Hierzu können Sie in der Anforderungszuweisungsvorlage eingabespezifische Validierungsschritte festlegen, bevor eine SQL-Anweisung für Ihre Daten-API ausgeführt wird. Sehen wir uns an, wie wir die Anforderungszuweisungsvorlage des Beispiels `listPetsByPriceRange` anpassen können. Statt sich ausschließlich auf die Benutzereingabe zu verlassen, können Sie wie folgt verfahren:

```
#set($validMaxPrice = $util.matches("\d{1,3}[,\\.]?(\\d{1,2})?",$ctx.args.maxPrice))

#set($validMinPrice = $util.matches("\d{1,3}[,\\.]?(\\d{1,2})?",$ctx.args.minPrice))


#if (!$validMaxPrice || !$validMinPrice)
    $util.error("Provided price input is not valid.")
#end
{
    "version": "2018-05-29",
    "statements": [
            "select * from Pets where price > :MIN and price < :MAX"
    ],

    "variableMap": {
        ":MAX": $util.toJson($ctx.args.maxPrice),
        ":MIN": $util.toJson($ctx.args.minPrice)
    }
}
```

Eine weitere Möglichkeit zum Schutz vor nicht autorisierten Eingaben beim Ausführen der Resolver gegen Ihre Daten-API bieten vorbereitete Anweisungen mit gespeicherter Prozedur und parametrisierten Eingaben. Beispiel: Definieren Sie im Resolver `listPets` die folgende Prozedur, die *Select* als vorbereitete Anweisung ausführt:

```
CREATE PROCEDURE listPets (IN type_param VARCHAR(200))
  BEGIN
     PREPARE stmt FROM 'SELECT * FROM Pets where type=?';
     SET @type = type_param;
     EXECUTE stmt USING @type;
     DEALLOCATE PREPARE stmt;
  END
```

Erstellen Sie dies in Ihrer Aurora Serverless v2-Instance.

```
aws rds-data execute-statement --resource-arn "arn:aws:rds:us-east-1:xxxxxxxxxxxx:cluster:http-endpoint-test" \
--schema "mysql"  --secret-arn "arn:aws:secretsmanager:us-east-1:xxxxxxxxxxxx:secret:httpendpoint-xxxxxx"  \
--region us-east-1  --database "DB_NAME" \
--sql "CREATE PROCEDURE listPets (IN type_param VARCHAR(200)) BEGIN PREPARE stmt FROM 'SELECT * FROM Pets where type=?'; SET @type = type_param; EXECUTE stmt USING @type; DEALLOCATE PREPARE stmt; END"
```

Der resultierende Resolver-Code für listPets wird vereinfacht, da wir jetzt einfach die gespeicherte Prozedur aufrufen. Als Mindestanforderung müssen bei jeder Zeichenfolgeneingabe einfache Anführungszeichen [durch Escape-Zeichen geschützt sein](#escaped).

```
#set ($validType = $util.isString($ctx.args.type) && !$util.isNullOrBlank($ctx.args.type))
#if (!$validType)
    $util.error("Input for 'type' is not valid.", "ValidationError")
#end

{
    "version": "2018-05-29",
    "statements": [
        "CALL listPets(:type)"
    ]
    "variableMap": {
        ":type": $util.toJson($ctx.args.type.replace("'", "''"))
    }
}
```

### Verwenden von Escape-Zeichenketten
<a name="escaped"></a>

Verwenden Sie einfache Anführungszeichen, um den Anfang und das Ende von Zeichenkettenliteralen in einer SQL-Anweisung zu markieren, z. `'some string value'`. Damit Zeichenfolgenwerte mit einem oder mehreren einfachen Anführungszeichen (`'`) innerhalb einer Zeichenfolge verwendet werden können, muss jedes durch zwei einfache Anführungszeichen (`''`) ersetzt werden. Lautet die Eingabezeichenfolge beispielsweise `Nadia's dog`, würden Sie sie für die SQL-Anweisung wie folgt durch Escape-Zeichen schützen:

```
update Pets set type='Nadia''s dog' WHERE id='1'
```

# Verwendung von Pipeline-Resolvern in AWS AppSync
<a name="tutorial-pipeline-resolvers"></a>

**Anmerkung**  
Wir unterstützen jetzt hauptsächlich die APPSYNC\$1JS-Laufzeit und ihre Dokumentation. [Bitte erwägen Sie, die APPSYNC\$1JS-Laufzeit und ihre Anleitungen hier zu verwenden.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

AWS AppSync bietet eine einfache Möglichkeit, ein GraphQL-Feld über Unit-Resolver mit einer einzelnen Datenquelle zu verbinden. Eine einzige Operation auszuführen, reicht jedoch möglicherweise nicht aus. Pipeline-Resolver bieten die Möglichkeit einer seriellen Ausführung von Operationen auf Datenquellen. Erstellen Sie Funktionen in Ihrer API und verbinden Sie diese mit einem Pipeline-Resolver. Jedes Ergebnis einer Funktionsausführung wird an die nächste Funktion weitergeleitet, bis keine weitere Funktion mehr auszuführen ist. Mit Pipeline-Resolvern können Sie jetzt direkt in AWS AppSync komplexere Workflows erstellen. In diesem Tutorial erstellen Sie eine einfache App für die Anzeige von Bildern, in der Benutzer Bilder veröffentlichen und von ihren Freunden veröffentlichte Bilder anzeigen können.

## One-Click-Setup
<a name="one-click-setup"></a>

Wenn Sie den GraphQL-Endpunkt automatisch AWS AppSync mit allen konfigurierten Resolvern und den erforderlichen AWS Ressourcen einrichten möchten, können Sie die folgende AWS CloudFormation Vorlage verwenden:

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

Dieser Stack erstellt die folgenden Ressourcen in Ihrem Konto:
+ IAM-Rolle für den Zugriff AWS AppSync auf die Ressourcen in Ihrem Konto
+ 2 DynamoDB-Tabellen
+ 1 Amazon Cognito-Benutzerpool
+ 2 Amazon Cognito-Benutzerpoolgruppen
+ 3 Amazon Cognito-Benutzerpoolbenutzer
+ 1 API AWS AppSync 

Am Ende des AWS CloudFormation Stack-Erstellungsprozesses erhalten Sie eine E-Mail für jeden der drei Amazon Cognito Cognito-Benutzer, die erstellt wurden. Jede E-Mail enthält ein temporäres Passwort, mit dem Sie sich als Amazon Cognito Cognito-Benutzer an der AWS AppSync Konsole anmelden. Speichern Sie die Passwörter, damit Sie während des Tutorials darauf zurückgreifen können.

## Manuelle Einrichtung
<a name="manual-setup"></a>

Wenn Sie es vorziehen, einen step-by-step Vorgang manuell über die AWS AppSync Konsole durchzuführen, folgen Sie dem unten stehenden Einrichtungsprozess.

### Richten Sie Ihre AWS AppSync Nicht-Ressourcen ein
<a name="setting-up-your-non-aws-appsync-resources"></a>

Die API kommuniziert mit zwei DynamoDB-Tabellen: einer **Bildertabelle, in der Bilder** gespeichert werden, und einer **Freundes-Tabelle**, in der Beziehungen zwischen Benutzern gespeichert werden. Die API wird für die Verwendung des Amazon Cognito-Benutzerpools als Authentifizierungstyp konfiguriert. Der folgende CloudFormation Stack richtet diese Ressourcen im Konto ein.

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

Am Ende des AWS CloudFormation Stack-Erstellungsprozesses erhalten Sie eine E-Mail für jeden der drei Amazon Cognito Cognito-Benutzer, die erstellt wurden. Jede E-Mail enthält ein temporäres Passwort, mit dem Sie sich als Amazon Cognito-Benutzer bei der AWS AppSync-Konsole anmelden. Speichern Sie die Passwörter, damit Sie während des Tutorials darauf zurückgreifen können.

### Erstellen der GraphQL-API
<a name="creating-your-graphql-api"></a>

Um die GraphQL-API zu erstellen in AWS AppSync:

1. Öffnen Sie die AWS AppSync Konsole und wählen Sie **Build From Scratch** und dann **Start**.

1. Legen Sie den Namen der API auf `AppSyncTutorial-PicturesViewer` fest.

1. Wählen Sie **Erstellen** aus.

Die AWS AppSync Konsole erstellt mithilfe des API-Schlüsselauthentifizierungsmodus eine neue GraphQL-API für Sie. Sie können in der Konsole den Rest der GraphQL-API einrichten und im weiteren Verlauf dieses Tutorials abfragen.

### Konfigurieren der GraphQL-API
<a name="configuring-the-graphql-api"></a>

Sie müssen die AWS AppSync API mit dem Amazon Cognito Cognito-Benutzerpool konfigurieren, den Sie gerade erstellt haben.

1. Wählen Sie die Registerkarte **Einstellungen**.

1. Wählen Sie im Abschnitt **Authorization Type (Autorisierungstyp)** *Amazon Cognito User Pool (Amazon Cognito-Benutzerpool)* aus.

1. *Wählen Sie unter **Benutzerpool-Konfiguration** die Option **US-WEST-2** für die Region aus.AWS *

1. Wählen Sie den UserPool Benutzerpool **AppSyncTutorial-** aus.

1. Wählen Sie **DENY (VERWEIGERN)** als *Default Action (Standardaktion)* aus.

1. Lassen Sie das **AppId Client-Regex-Feld leer**.

1. Wählen Sie **Speichern**.

Die API ist jetzt für die Verwendung des Amazon Cognito-Benutzerpools als Autorisierungstyp eingerichtet.

### Konfiguration von Datenquellen für die DynamoDB-Tabellen
<a name="configuring-data-sources-for-the-ddb-tables"></a>

Nachdem die DynamoDB-Tabellen erstellt wurden, navigieren Sie in der Konsole zu Ihrer AWS AppSync GraphQL-API und wählen Sie die Registerkarte **Datenquellen**. Jetzt erstellen Sie eine Datenquelle AWS AppSync für jede der DynamoDB-Tabellen, die Sie gerade erstellt haben.

1. Klicken Sie auf die Registerkarte **Data source (Datenquelle)**.

1. Wählen Sie **New (Neu)** aus, um eine neue Datenquelle zu erstellen.

1. Geben Sie als Namen für die Datenquelle `PicturesDynamoDBTable` ein.

1. Wählen Sie als Typ der Datenquelle **Amazon DynamoDB table (Amazon DynamoDB-Tabelle)** aus.

1. Wählen Sie **US-WEST-2** als Region aus.

1. Wählen Sie aus der Tabellenliste die **AppSyncTutorialDynamoDB-Tabelle -Pictures** aus.

1. **Wählen **Sie im Abschnitt Eine bestehende Rolle erstellen oder verwenden die Option Bestehende Rolle** aus.**

1. Wählen Sie die Rolle aus, die gerade aus der CloudFormation Vorlage erstellt wurde. Wenn Sie die nicht geändert haben *ResourceNamePrefix*, sollte der Name der Rolle **AppSyncTutorial-Dynamo lauten DBRole**.

1. Wählen Sie **Erstellen** aus.

Wiederholen Sie den Vorgang für die **Friends-Tabelle**. Der Name der DynamoDB-Tabelle sollte **AppSyncTutorial-Friends lauten**, wenn Sie den *ResourceNamePrefix*Parameter bei der Erstellung des Stacks nicht geändert haben. CloudFormation 

### Erstellen des GraphQL-Schemas
<a name="creating-the-graphql-schema"></a>

Nachdem die Datenquellen nun mit Ihren DynamoDB-Tabellen verbunden sind, erstellen wir ein GraphQL-Schema. Stellen Sie im Schema-Editor in der AWS AppSync Konsole sicher, dass Ihr Schema dem folgenden Schema entspricht:

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

type Mutation {
    createPicture(input: CreatePictureInput!): Picture!
    @aws_auth(cognito_groups: ["Admins"])
    createFriendship(id: ID!, target: ID!): Boolean
    @aws_auth(cognito_groups: ["Admins"])
}

type Query {
    getPicturesByOwner(id: ID!): [Picture]
    @aws_auth(cognito_groups: ["Admins", "Viewers"])
}

type Picture {
    id: ID!
    owner: ID!
    src: String
}

input CreatePictureInput {
    owner: ID!
    src: String!
}
```

Klicken Sie auf **Save Schema (Schema speichern)**, um Ihr Schema zu speichern.

Einige Schemafelder wurden mit der Richtlinie *@aws\$1auth* kommentiert. Da für die Konfiguration der Standardaktion der API *DENY (VERWEIGERN)* festgelegt ist, lehnt die API alle Benutzer ab, die kein Mitglied der in der Richtlinie *@aws\$1auth* aufgeführten Gruppen sind. Weitere Informationen zum Schutz Ihrer API finden Sie unter [Security (Sicherheit)](security-authz.md#aws-appsync-security). *In diesem Fall haben nur Admin-Benutzer Zugriff auf die Felder *Mutation.CreatePicture und *Mutation.CreateFriendship**, während Benutzer, die entweder Mitglieder der *Admins* - oder Viewers-Gruppen sind, auf die Query zugreifen können.* * getPicturesByFeld „Besitzer“.* Alle anderen Benutzer haben keinen Zugriff.

### Konfigurieren von Resolvern
<a name="configuring-resolvers"></a>

Nachdem Sie jetzt ein gültiges GraphQL-Schema und zwei Datenquellen besitzen, können Sie Resolver mit den GraphQL-Feldern auf dem Schema verbinden. Die API bietet folgende Funktionen:
+ Erstellen eines Bildes über das Feld *Mutation.createPicture*
+ Erstellen einer Freundschaft über das Feld *Mutation.createFriendship*
+ Abrufen eines Bildes über das Feld *Query.getPicture*

#### Mutation.createPicture
<a name="mutation-createpicture"></a>

Wählen Sie im Schema-Editor in der AWS AppSync Konsole auf der rechten Seite **Attach Resolver** for `createPicture(input: CreatePictureInput!): Picture!` aus. Wählen Sie die DynamoDB-Datenquelle *PicturesDynamoDBTable*aus. Fügen Sie die folgende Vorlage im Abschnitt **request mapping template (Zuweisungsvorlage für Anforderungen)** ein:

```
#set($id = $util.autoId())

{
    "version" : "2018-05-29",

    "operation" : "PutItem",

    "key" : {
        "id" : $util.dynamodb.toDynamoDBJson($id),
        "owner": $util.dynamodb.toDynamoDBJson($ctx.args.input.owner)
    },

    "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args.input)
}
```

Fügen Sie die folgende Vorlage im Abschnitt **response mapping template (Zuweisungsvorlage für Antworten)** ein:

```
#if($ctx.error)
    $util.error($ctx.error.message, $ctx.error.type)
#end
$util.toJson($ctx.result)
```

Die Funktion zum Erstellen eines Bildes ist fertig. Ein Bild wird in der Tabelle **Pictures** mit einer zufällig generierte UUID als ID des Bildes und unter Verwendung des Cognito-Benutzernamens für den Eigentümer des Bildes gespeichert.

#### Mutation.createFriendship
<a name="mutation-createfriendship"></a>

Wählen Sie im Schema-Editor in der AWS AppSync Konsole auf der rechten Seite **Attach Resolver** for aus. `createFriendship(id: ID!, target: ID!): Boolean` Wählen Sie die DynamoDB-Datenquelle **FriendsDynamoDBTable**aus. Fügen Sie die folgende Vorlage im Abschnitt **request mapping template (Zuweisungsvorlage für Anforderungen)** ein:

```
#set($userToFriendFriendship = { "userId" : "$ctx.args.id", "friendId": "$ctx.args.target" })
#set($friendToUserFriendship = { "userId" : "$ctx.args.target", "friendId": "$ctx.args.id" })
#set($friendsItems = [$util.dynamodb.toMapValues($userToFriendFriendship), $util.dynamodb.toMapValues($friendToUserFriendship)])

{
    "version" : "2018-05-29",
    "operation" : "BatchPutItem",
    "tables" : {
        ## Replace 'AppSyncTutorial-' default below with the ResourceNamePrefix you provided in the CloudFormation template
        "AppSyncTutorial-Friends": $util.toJson($friendsItems)
    }
}
```

Wichtig: In der **BatchPutItem**Anforderungsvorlage sollte der genaue Name der DynamoDB-Tabelle vorhanden sein. *Der Standardtabellenname ist AppSyncTutorial -Friends.* Wenn Sie den falschen Tabellennamen verwenden, erhalten Sie eine Fehlermeldung, wenn Sie AppSync versuchen, die angegebene Rolle anzunehmen.

Gehen Sie in diesem Tutorial der Einfachheit halber so vor, als ob die Freundschaftsanfrage genehmigt worden wäre, und speichern Sie den Beziehungseintrag direkt in der **AppSyncTutorialFriends**Tabelle.

Da die Beziehung bidirektional ist, werden für jede Freundschaft faktisch zwei Elemente gespeichert. Weitere Informationen zu den bewährten Methoden von Amazon DynamoDB zur Darstellung von many-to-many Beziehungen finden Sie unter Bewährte Methoden für [DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-adjacency-graphs.html).

Fügen Sie die folgende Vorlage im Abschnitt **response mapping template (Zuweisungsvorlage für Antworten)** ein:

```
#if($ctx.error)
    $util.error($ctx.error.message, $ctx.error.type)
#end
true
```

Hinweis: Stellen Sie sicher, dass Ihre Anforderungsvorlage den richtigen Tabellennamen enthält. Der Standardname ist *AppSyncTutorial-Friends*, aber Ihr Tabellenname könnte abweichen, wenn Sie den Parameter ändern. CloudFormation **ResourceNamePrefix**

#### Abfrage. getPicturesByBesitzer
<a name="query-getpicturesbyowner"></a>

Nachdem Sie jetzt Freundschaften und Bilder besitzen, müssen Sie Benutzern die Möglichkeit bieten, die Bilder ihrer Freunde anzuzeigen. Um diese Anforderung zu erfüllen, müssen Sie zuerst prüfen, ob der Anforderer mit dem Eigentümer befreundet ist und anschließend die Bilder abrufen.

Da für diese Funktionalität zwei Datenquellenoperationen erforderlich sind, müssen Sie zwei Funktionen erstellen. Die erste Funktion, **isFriend**, prüft, ob der Anforderer und der Eigentümer Freunde sind. Die zweite Funktion, **getPicturesByBesitzer**, ruft die angeforderten Bilder mit einer Besitzer-ID ab. *Schauen wir uns unten den Ausführungsablauf für den vorgeschlagenen Resolver in der Abfrage an. getPicturesByFeld „Besitzer*“:

1. Vorher-Zuweisungsvorlage: Bereitet den Kontext und die Eingabeargumente für das Feld vor.

1. isFriend-Funktion: Prüft, ob der Anforderer der Eigentümer des Bildes ist. Wenn nicht, überprüft es, ob die Benutzer des Anforderers und des Besitzers Freunde sind, indem es eine GetItem DynamoDB-Operation in der Friends-Tabelle ausführt.

1. getPicturesByOwner-Funktion: Ruft mithilfe einer DynamoDB-Abfrageoperation für den globalen Sekundärindex des *Eigentümerindexes* Bilder aus der Tabelle Pictures ab.

1. Nachher-Zuweisungsvorlage: Weist die resultierenden Bilder so zu, dass die DynamoDB-Attribute den erwarteten Feldern des GraphQL-Typs korrekt zugewiesen sind.

Erstellen wir zuerst die Funktionen.

##### isFriend-Funktion
<a name="isfriend-function"></a>

1. Wählen Sie die Registerkarte **Functions (Funktionen)** aus.

1. Wählen Sie **Create Function (Funktion erstellen)** aus, um eine Funktion zu erstellen.

1. Geben Sie als Namen für die Datenquelle `FriendsDynamoDBTable` ein.

1. Geben Sie für den Namen der Funktion *isFriend* ein.

1. Fügen Sie die folgende Vorlage in den Textbereich der Zuweisungsvorlage für Anforderungen ein:

   ```
   #set($ownerId = $ctx.prev.result.owner)
   #set($callerId = $ctx.prev.result.callerId)
   
   ## if the owner is the caller, no need to make the check
   #if($ownerId == $callerId)
       #return($ctx.prev.result)
   #end
   
   {
       "version" : "2018-05-29",
   
       "operation" : "GetItem",
   
       "key" : {
           "userId" : $util.dynamodb.toDynamoDBJson($callerId),
           "friendId" : $util.dynamodb.toDynamoDBJson($ownerId)
       }
   }
   ```

1. Fügen Sie die folgende Vorlage in den Textbereich der Zuweisungsvorlage für Antworten ein:

   ```
   #if($ctx.error)
       $util.error("Unable to retrieve friend mapping message: ${ctx.error.message}", $ctx.error.type)
   #end
   
   ## if the users aren't friends
   #if(!$ctx.result)
       $util.unauthorized()
   #end
   
   $util.toJson($ctx.prev.result)
   ```

1. Wählen Sie **Create Function**.

Ergebnis: Sie haben die Funktion **isFriend** erstellt.

##### getPicturesByFunktion „Besitzer“
<a name="getpicturesbyowner-function"></a>

1. Wählen Sie die Registerkarte **Functions (Funktionen)** aus.

1. Wählen Sie **Create Function (Funktion erstellen)** aus, um eine Funktion zu erstellen.

1. Geben Sie als Namen für die Datenquelle `PicturesDynamoDBTable` ein.

1. Geben Sie für den Namen der Funktion `getPicturesByOwner` ein.

1. Fügen Sie die folgende Vorlage in den Textbereich der Zuweisungsvorlage für Anforderungen ein:

   ```
   {
       "version" : "2018-05-29",
   
       "operation" : "Query",
   
       "query" : {
           "expression": "#owner = :owner",
           "expressionNames": {
               "#owner" : "owner"
           },
           "expressionValues" : {
               ":owner" : $util.dynamodb.toDynamoDBJson($ctx.prev.result.owner)
           }
       },
   
       "index": "owner-index"
   }
   ```

1. Fügen Sie die folgende Vorlage in den Textbereich der Zuweisungsvorlage für Antworten ein:

   ```
   #if($ctx.error)
       $util.error($ctx.error.message, $ctx.error.type)
   #end
   
   $util.toJson($ctx.result)
   ```

1. Wählen Sie **Create Function**.

Ergebnis: Sie haben die Funktion **getPicturesByBesitzer** erstellt. Nachdem die Funktionen erstellt wurden, fügen Sie der *Abfrage einen Pipeline-Resolver hinzu. getPicturesByFeld „Besitzer*“.

Wählen Sie im Schema-Editor in der AWS AppSync Konsole auf der rechten Seite **Attach Resolver** for `Query.getPicturesByOwner(id: ID!): [Picture]` aus. Klicken Sie auf der folgenden Seite auf den Link **Convert to pipeline resolver (In Pipeline-Resolver konvertieren)**, der unter der Dropdown-Liste der Datenquellen angezeigt wird. Verwenden Sie Folgendes für die Zuweisungsvorlage für Antworten:

```
#set($result = { "owner": $ctx.args.id, "callerId": $ctx.identity.username })
$util.toJson($result)
```

Verwenden Sie Folgendes für die **Nachher-Zuweisungsvorlage**:

```
#foreach($picture in $ctx.result.items)
    ## prepend "src://" to picture.src property
    #set($picture['src'] = "src://${picture['src']}")
#end
$util.toJson($ctx.result.items)
```

Wählen Sie **Create Resolver (Resolver erstellen)** aus. Sie haben erfolgreich Ihren ersten Pipeline-Resolver angefügt. Fügen Sie auf derselben Seite die beiden zuvor erstellten Funktionen hinzu. Wählen Sie im Abschnitt für Funktionen **Add A Funktion (Funktion hinzufügen)** aus. Wählen Sie dann den Namen der ersten Funktion, **isFriend**, aus oder geben Sie ihn ein. Fügen Sie die zweite Funktion hinzu, indem Sie den gleichen Vorgang für die Funktion **getPicturesByOwner ausführen**. Stellen Sie sicher, dass die Funktion **IsFriend** zuerst in der Liste erscheint, gefolgt von der Funktion **getPicturesByBesitzer**. Mit den Pfeilen nach oben und unten können Sie die Ausführungsreihenfolge der Funktionen in der Pipeline verändern.

Nachdem der Pipeline-Resolver erstellt wurde und Sie die Funktionen angehängt haben, wollen wir die neu erstellte GraphQL-API testen.

## Testen der GraphQL-API
<a name="testing-your-graphql-api"></a>

Zuerst müssen Sie Bilder und Freundschaften auffüllen, indem Sie mit dem erstellten Admin-Benutzer ein paar Mutationen ausführen. Wählen Sie auf der linken Seite der AWS AppSync Konsole die Registerkarte **Abfragen** aus.

### createPicture-Mutation
<a name="createpicture-mutation"></a>

1. Wählen Sie in der AWS AppSync Konsole die Registerkarte **Abfragen** aus.

1. Wählen Sie **Login With User Pools (Anmeldung mit Benutzerpools)** aus.

1. Geben Sie im Modal die Cognito Sample Client ID ein, die vom CloudFormation Stack erstellt wurde (z. B. 37solo6mmhh7k4v63cqdfgdg5d).

1. Geben Sie den Benutzernamen ein CloudFormation , den Sie als Parameter an den Stack übergeben haben. Der Standardwert lautet **nadia**.

1. Verwenden Sie das temporäre Passwort, das an die von Ihnen angegebene E-Mail gesendet wurde, als Parameter für den CloudFormation Stack (z. B. *UserPoolUserEmail*).

1. Wählen Sie **Login (Anmelden)** aus. Sie sollten jetzt sehen, dass die Schaltfläche in **Logout nadia** umbenannt wurde, oder in einen anderen Benutzernamen, den Sie bei der Erstellung des CloudFormation Stacks gewählt haben (d. h. *UserPoolUsername*).

Lassen Sie uns nun einige *createPicture*-Mutationen senden, um die Tabelle mit Bildern zu füllen. Führen Sie die folgende GraphQL-Abfrage in der Konsole aus:

```
mutation {
  createPicture(input:{
    owner: "nadia"
    src: "nadia.jpg"
  }) {
    id
    owner
    src
  }
}
```

Die Antwort sollte wie folgt aussehen:

```
{
  "data": {
    "createPicture": {
      "id": "c6fedbbe-57ad-4da3-860a-ffe8d039882a",
      "owner": "nadia",
      "src": "nadia.jpg"
    }
  }
}
```

Lassen Sie uns noch einige weitere Bilder hinzufügen:

```
mutation {
  createPicture(input:{
    owner: "shaggy"
    src: "shaggy.jpg"
  }) {
    id
    owner
    src
  }
}
```

```
mutation {
  createPicture(input:{
    owner: "rex"
    src: "rex.jpg"
  }) {
    id
    owner
    src
  }
}
```

Sie haben mit **nadia** als Admin-Benutzer drei Bilder hinzugefügt.

### createFriendship-Mutation
<a name="createfriendship-mutation"></a>

Lassen Sie uns einen Freundschaftseintrag hinzufügen. Führen Sie die folgenden Mutationen in der Konsole aus.

Hinweis: Sie müssen weiterhin als Admin-Benutzer angemeldet sein (der standardmäßige Admin-Benutzer ist **nadia**).

```
mutation {
  createFriendship(id: "nadia", target: "shaggy")
}
```

Die Antwort sollte wie folgt aussehen:

```
{
  "data": {
    "createFriendship": true
  }
}
```

 **nadia** und **shaggy** sind Freunde. **rex** ist mit niemandem befreundet.

### getPicturesByBesitzer-Anfrage
<a name="getpicturesbyowner-query"></a>

Melden Sie sich für diesen Schritt mithilfe von Cognito-Benutzerpools als Benutzer **nadia** an, indem Sie die zu Beginn dieses Tutorials eingerichteten Anmeldeinformationen verwenden. Rufen Sie als **nadia** die Bilder im Besitz von **shaggy** ab.

```
query {
    getPicturesByOwner(id: "shaggy") {
        id
        owner
        src
    }
}
```

Da **nadia** und **shaggy** Freunde sind, gibt die Abfrage das entsprechende Bild zurück.

```
{
  "data": {
    "getPicturesByOwner": [
      {
        "id": "05a16fba-cc29-41ee-a8d5-4e791f4f1079",
        "owner": "shaggy",
        "src": "src://shaggy.jpg"
      }
    ]
  }
}
```

**nadia** kann auch ihre eigenen Bilder erfolgreich abrufen. Der Pipeline-Resolver wurde so optimiert, dass in diesem Fall die ** GetItem IsFriend-Operation** nicht ausgeführt wird. Versuchen Sie, die folgende Abfrage auszuführen:

```
query {
    getPicturesByOwner(id: "nadia") {
        id
        owner
        src
    }
}
```

Wenn Sie die Protokollierung auf Ihrer API aktiviert haben (im Bereich **Settings (Einstellungen)**), legen Sie für die Debugging-Stufe **ALL** fest und führen Sie die gleiche Abfrage erneut, damit Protokolle für die Feldausführung zurückgegeben werden. In den Protokollen können Sie prüfen, ob die Rückgabe der Funktion **isFriend** zu einem frühen Zeitpunkt während der Phase der **Zuweisungsvorlage für Anforderungen** erfolgt ist:

```
{
  "errors": [],
  "mappingTemplateType": "Request Mapping",
  "path": "[getPicturesByOwner]",
  "resolverArn": "arn:aws:appsync:us-west-2:XXXX:apis/XXXX/types/Query/fields/getPicturesByOwner",
  "functionArn": "arn:aws:appsync:us-west-2:XXXX:apis/XXXX/functions/o2f42p2jrfdl3dw7s6xub2csdfs",
  "functionName": "isFriend",
  "earlyReturnedValue": {
    "owner": "nadia",
    "callerId": "nadia"
  },
  "context": {
    "arguments": {
      "id": "nadia"
    },
    "prev": {
      "result": {
        "owner": "nadia",
        "callerId": "nadia"
      }
    },
    "stash": {},
    "outErrors": []
  },
  "fieldInError": false
}
```

Der *earlyReturnedValue*Schlüssel stellt die Daten dar, die von der *\$1return* -Direktive zurückgegeben wurden.

**Schließlich wird **Rex**, obwohl er Mitglied der **Viewers** Cognito UserPool Group ist und weil **Rex** mit niemandem befreundet ist, auf keines der Bilder zugreifen können, die **Shaggy** oder Nadia gehören.** Wenn Sie sich als **rex** in der Konsole anmelden und die folgende Abfrage ausführen:

```
query {
    getPicturesByOwner(id: "nadia") {
        id
        owner
        src
    }
}
```

Sie erhalten folgenden Fehler wegen fehlender Autorisierung:

```
{
  "data": {
    "getPicturesByOwner": null
  },
  "errors": [
    {
      "path": [
        "getPicturesByOwner"
      ],
      "data": null,
      "errorType": "Unauthorized",
      "errorInfo": null,
      "locations": [
        {
          "line": 2,
          "column": 9,
          "sourceName": null
        }
      ],
      "message": "Not Authorized to access getPicturesByOwner on type Query"
    }
  ]
}
```

Sie haben erfolgreich eine komplexe Autorisierung mit Pipeline-Resolvern implementiert.

# Verwenden von Delta Sync-Vorgängen für versionierte Datenquellen in AWS AppSync
<a name="tutorial-delta-sync"></a>

**Anmerkung**  
Wir unterstützen jetzt hauptsächlich die APPSYNC\$1JS-Laufzeit und ihre Dokumentation. [Bitte erwägen Sie, die APPSYNC\$1JS-Laufzeit und ihre Anleitungen hier zu verwenden.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

Client-Anwendungen AWS AppSync speichern Daten, indem sie GraphQL-Antworten lokal auf der Festplatte in einer mobile/web Anwendung zwischenspeichern. Versionierte Datenquellen und `Sync`-Vorgänge bieten Kunden die Möglichkeit, den Synchronisierungsprozess mit einem einzigen Resolver durchzuführen. Auf diese Weise können Clients ihren lokalen Cache mit Ergebnissen aus einer Basis-Abfrage, die möglicherweise viele Datensätze enthalten, hydratisieren und anschließend nur die Daten empfangen, die seit der letzten Abfrage geändert wurden (die *Delta-Updates*). Indem Clients berechtigt werden, die Basis-Hydration des Caches mit einer Abfrage und inkrementelle Updates mit einer anderen Abfrage separat durchzuführen, können die Rechenvorgänge von der Client-Anwendung in das Backend verlagert werden. Dies ist wesentlich effizienter für Client-Anwendungen, die häufig zwischen Online- und Offline-Status wechseln.

Um Delta Sync zu implementieren, verwendet die `Sync`-Abfrage den `Sync`-Vorgang für eine versionierte Datenquelle. Wenn eine AWS AppSync Mutation ein Element in einer versionierten Datenquelle ändert, wird ein Datensatz dieser Änderung ebenfalls in der *Delta-Tabelle* gespeichert. Sie können wählen, ob Sie verschiedene *Delta-Tabellen* (z. B. eine pro Typ, eine pro Domainbereich) für andere versionierte Datenquellen oder eine einzelne *Delta-Tabelle* für Ihre API verwenden möchten. AWS AppSync empfiehlt, keine einzige *Delta-Tabelle* für mehrere APIs zu verwenden, um die Kollision von Primärschlüsseln zu vermeiden.

Darüber hinaus können Delta Sync-Clients auch ein Abonnement als Argument erhalten. Der Client koordiniert dann das Wiederherstellen von Abonnementverbindungen und Schreibvorgänge während des Übergangs vom Offline- zum Online-Zustand. Delta Sync führt hierzu eine automatische Wiederaufnahme der Abonnements durch, einschließlich exponentiellem Backoff und Neuversuch mit Jitter in verschiedenen Netzwerkfehlerszenarien und Speichern der Ereignisse in einer Warteschlange. Die entsprechende Delta- oder Basisabfrage wird dann ausgeführt, bevor Ereignisse aus der Warteschlange zusammengeführt und letztlich Abonnements wie gewohnt verarbeitet werden.

Die Dokumentation zu den Client-Konfigurationsoptionen, einschließlich Amplify DataStore, ist auf der [Amplify Framework-Website](https://aws-amplify.github.io/) verfügbar. In dieser Dokumentation wird beschrieben, wie Sie versionierte DynamoDB-Datenquellen und `Sync`-Vorgänge so einrichten, dass sie mit dem Delta Sync-Client für optimalen Datenzugriff arbeiten.

## One-Click-Setup
<a name="one-click-setup"></a>

Verwenden Sie diese Vorlage, um den GraphQL-Endpunkt AWS AppSync mit allen konfigurierten Resolvern und den erforderlichen AWS Ressourcen automatisch einzurichten: AWS CloudFormation 

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

Dieser Stack erstellt die folgenden Ressourcen in Ihrem Konto:
+ 2 DynamoDB-Tabellen (Base und Delta)
+ 1 AWS AppSync API mit API-Schlüssel
+ 1 IAM-Rolle mit Richtlinie für DynamoDB-Tabellen

Es werden zwei Tabellen verwendet, um Ihre Sync-Abfragen in eine zweite Tabelle zu partitionieren, die als Journal der Ereignisse fungiert, welche verpasst wurden, während die Clients offline waren. Um die Abfragen in der Delta-Tabelle effizient zu halten, TTLs werden [Amazon DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html) verwendet, um die Ereignisse bei Bedarf automatisch zu bereinigen. Die TTL-Zeit ist für Ihre Anforderungen an die Datenquelle konfigurierbar (Sie können dies als 1 Stunde, 1 Tag usw. verwenden).

## Schema
<a name="schema"></a>

Um Delta Sync zu demonstrieren, erstellt die Beispielanwendung ein *Posts-Schema*, das von einer *Base* - und *Delta-Tabelle* in DynamoDB unterstützt wird. AWS AppSync schreibt die Mutationen automatisch in beide Tabellen. Die Sync-Abfrage ruft Datensätze entsprechend aus der *Basis*- oder der *Delta*-Tabelle ab. Außerdem ist ein einziges Abonnement definiert, das zeigt, wie die Clients dies in ihrer Logik für erneute Verbindungen nutzen können.

```
input CreatePostInput {
    author: String!
    title: String!
    content: String!
    url: String
    ups: Int
    downs: Int
    _version: Int
}

interface Connection {
  nextToken: String
  startedAt: AWSTimestamp!
}

type Mutation {
    createPost(input: CreatePostInput!): Post
    updatePost(input: UpdatePostInput!): Post
    deletePost(input: DeletePostInput!): Post
}

type Post {
    id: ID!
    author: String!
    title: String!
    content: String!
    url: AWSURL
    ups: Int
    downs: Int
    _version: Int
    _deleted: Boolean
    _lastChangedAt: AWSTimestamp!
}

type PostConnection implements Connection {
    items: [Post!]!
    nextToken: String
    startedAt: AWSTimestamp!
}

type Query {
    getPost(id: ID!): Post
    syncPosts(limit: Int, nextToken: String, lastSync: AWSTimestamp): PostConnection!
}

type Subscription {
    onCreatePost: Post
        @aws_subscribe(mutations: ["createPost"])
    onUpdatePost: Post
        @aws_subscribe(mutations: ["updatePost"])
    onDeletePost: Post
        @aws_subscribe(mutations: ["deletePost"])
}

input DeletePostInput {
    id: ID!
    _version: Int!
}

input UpdatePostInput {
    id: ID!
    author: String
    title: String
    content: String
    url: String
    ups: Int
    downs: Int
    _version: Int!
}

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

Das GraphQL-Schema ist Standard. Einige Aspekte sind jedoch der Erwähnung wert, bevor Sie fortfahren. Zuerst werden alle Mutationen automatisch in die *Basis*-Tabelle und dann in die *Delta*-Tabelle geschrieben. Die *Basis*-Tabelle ist die zentrale Datenquelle (Single Source of Truth) für den Status, während die *Delta*-Tabelle Ihr Journal ist. Wenn Sie die `lastSync: AWSTimestamp` nicht übergeben, wird die `syncPosts`-Abfrage über die *Basis*-Tabelle ausgeführt. Sie hydratisiert den Cache und wird regelmäßig als *globaler Catchup-Prozess* für Sonderfälle ausgeführt, in denen Clients länger als die in der *Delta*-Tabelle konfigurierte TTL-Zeit offline sind. Wenn Sie die `lastSync: AWSTimestamp`-Abfrage jedoch übergeben, wird die `syncPosts`-Abfrage über die *Delta*-Tabelle ausgeführt und von Clients verwendet, um Ereignisse abzurufen, die seit ihrem letzte Offline-Zeitpunkt geändert wurden. Amplify-Clients übergeben den `lastSync: AWSTimestamp`-Wert automatisch und halten ihn entsprechend dauerhaft auf der Festplatte.

Das Feld *\$1deleted* auf *Post* wird für **DELETE**-Vorgänge verwendet. Wenn Clients offline sind und Datensätze aus der *Basis*-Tabelle entfernt werden, benachrichtigt dieses Attribut Clients, die eine Synchronisierung durchführen, dass sie Elemente aus ihrem lokalen Cache entfernen müssen. In Fällen, in denen Clients für längere Zeiträume offline sind und das Element entfernt wurde, bevor der Client diesen Wert mit einer Delta Sync-Abfrage abrufen kann, wird das globale Catchup-Ereignis in der Basis-Abfrage (im Client konfigurierbar) ausgeführt und entfernt das Element aus dem Cache. Dieses Feld ist als optional gekennzeichnet, weil es nur dann einen Wert zurückgibt, wenn es eine Sync-Abfrage ausführt, in der gelöschte Elemente vorhanden sind.

## Mutationen
<a name="mutations"></a>

 AWS AppSync Führt für alle Mutationen eine Create/Update/Delete Standardoperation in der *Basistabelle* aus und zeichnet die Änderung auch automatisch in der *Delta-Tabelle* auf. Sie können den Aufbewahrungszeitraum für Datensätze verlängern oder verkürzen, indem Sie den `DeltaSyncTableTTL`-Wert in der Datenquelle anpassen. Für Unternehmen, deren Daten häufigen Änderungen unterliegen, ist es sinnvoll, einen kurzen Zeitraum anzugeben. Wenn Ihre Clients für längere Zeiträume offline sind, kann es ratsam sein, einen längeren Zeitraum anzugeben.

## Sync-Abfragen
<a name="sync-queries"></a>

Die *Basisabfrage* ist ein DynamoDB-Synchronisierungsvorgang ohne Angabe eines `lastSync` Werts. Dies funktioniert in vielen Organisationen, weil die Basis-Abfrage nur beim Start und danach in regelmäßigen Abständen ausgeführt wird.

Die *Deltaabfrage* ist ein DynamoDB-Synchronisierungsvorgang mit einem angegebenen `lastSync` Wert. Die *Delta-Abfrage* wird jedes Mal ausgeführt, wenn der Client wieder in den Online-Zustand wechselt (sofern nicht die periodische Basis-Abfrage die Ausführung ausgelöst hat). Clients verfolgen automatisch das letzte Mal nach, als sie eine Abfrage zum Synchronisieren von Daten erfolgreich ausgeführt haben.

Wenn eine Delta-Abfrage ausgeführt wird, verwendet der Resolver der Abfrage `ds_pk` und `ds_sk`, um nur die Datensätze abzufragen, die seit der letzten Synchronisierung durch den Client geändert wurden. Der Client speichert die entsprechende GraphQL-Antwort.

Weitere Informationen zum Ausführen von Sync-Abfragen finden Sie in der [Dokumentation zu Synchronisierungsoperationen](aws-appsync-conflict-detection-and-sync-sync-operations.md).

## Beispiel
<a name="example"></a>

Beginnen wir zunächst mit dem Aufruf einer `createPost`-Mutation, um ein Element zu erstellen:

```
mutation create {
  createPost(input: {author: "Nadia", title: "My First Post", content: "Hello World"}) {
    id
    author
    title
    content
    _version
    _lastChangedAt
    _deleted
  }
}
```

Der Rückgabewert dieser Mutation sieht wie folgt aus:

```
{
  "data": {
    "createPost": {
      "id": "81d36bbb-1579-4efe-92b8-2e3f679f628b",
      "author": "Nadia",
      "title": "My First Post",
      "content": "Hello World",
      "_version": 1,
      "_lastChangedAt": 1574469356331,
      "_deleted": null
    }
  }
}
```

Wenn Sie den Inhalt der *Basis*-Tabelle untersuchen, wird ein Datensatz angezeigt, der wie folgt aussieht:

```
{
  "_lastChangedAt": {
    "N": "1574469356331"
  },
  "_version": {
    "N": "1"
  },
  "author": {
    "S": "Nadia"
  },
  "content": {
    "S": "Hello World"
  },
  "id": {
    "S": "81d36bbb-1579-4efe-92b8-2e3f679f628b"
  },
  "title": {
    "S": "My First Post"
  }
}
```

Wenn Sie den Inhalt der *Delta*-Tabelle untersuchen, wird ein Datensatz angezeigt, der wie folgt aussieht:

```
{
  "_lastChangedAt": {
    "N": "1574469356331"
  },
  "_ttl": {
    "N": "1574472956"
  },
  "_version": {
    "N": "1"
  },
  "author": {
    "S": "Nadia"
  },
  "content": {
    "S": "Hello World"
  },
  "ds_pk": {
    "S": "AppSync-delta-sync-post:2019-11-23"
  },
  "ds_sk": {
    "S": "00:35:56.331:81d36bbb-1579-4efe-92b8-2e3f679f628b:1"
  },
  "id": {
    "S": "81d36bbb-1579-4efe-92b8-2e3f679f628b"
  },
  "title": {
    "S": "My First Post"
  }
}
```

Jetzt können wir eine *Basis*-Abfrage simulieren, die von einem Client ausgeführt wird, um seinen lokalen Datenspeicher mit einer `syncPosts`-Abfrage zu hydratisieren, die wie folgt aussieht:

```
query baseQuery {
  syncPosts(limit: 100, lastSync: null, nextToken: null) {
    items {
      id
      author
      title
      content
      _version
      _lastChangedAt
    }
    startedAt
    nextToken
  }
}
```

Der Rückgabewert dieser *Basis*-Abfrage sieht wie folgt aus:

```
{
  "data": {
    "syncPosts": {
      "items": [
        {
          "id": "81d36bbb-1579-4efe-92b8-2e3f679f628b",
          "author": "Nadia",
          "title": "My First Post",
          "content": "Hello World",
          "_version": 1,
          "_lastChangedAt": 1574469356331
        }
      ],
      "startedAt": 1574469602238,
      "nextToken": null
    }
  }
}
```

Wir speichern den `startedAt`-Wert später, um eine *Delta*-Abfrage zu simulieren, aber zuerst müssen wir eine Änderung an unserer Tabelle vornehmen. Verwenden wir die `updatePost`-Mutation zum Ändern unseres vorhandenen Beitrags:

```
mutation updatePost {
  updatePost(input: {id: "81d36bbb-1579-4efe-92b8-2e3f679f628b", _version: 1, title: "Actually this is my Second Post"}) {
    id
    author
    title
    content
    _version
    _lastChangedAt
    _deleted
  }
}
```

Der Rückgabewert dieser Mutation sieht wie folgt aus:

```
{
  "data": {
    "updatePost": {
      "id": "81d36bbb-1579-4efe-92b8-2e3f679f628b",
      "author": "Nadia",
      "title": "Actually this is my Second Post",
      "content": "Hello World",
      "_version": 2,
      "_lastChangedAt": 1574469851417,
      "_deleted": null
    }
  }
}
```

Wenn Sie den Inhalt der *Basis*-Tabelle jetzt untersuchen, sollten Sie das aktualisierte Element sehen:

```
{
  "_lastChangedAt": {
    "N": "1574469851417"
  },
  "_version": {
    "N": "2"
  },
  "author": {
    "S": "Nadia"
  },
  "content": {
    "S": "Hello World"
  },
  "id": {
    "S": "81d36bbb-1579-4efe-92b8-2e3f679f628b"
  },
  "title": {
    "S": "Actually this is my Second Post"
  }
}
```

Wenn Sie den Inhalt der *Delta*-Tabelle jetzt untersuchen, sollten Sie zwei Datensätze sehen:

1. Ein Datensatz zum Zeitpunkt der Erstellung des Elements

1. Ein Datensatz zum Zeitpunkt der Aktualisierung des Elements.

Das neue Element sieht folgendermaßen aus:

```
{
  "_lastChangedAt": {
    "N": "1574469851417"
  },
  "_ttl": {
    "N": "1574473451"
  },
  "_version": {
    "N": "2"
  },
  "author": {
    "S": "Nadia"
  },
  "content": {
    "S": "Hello World"
  },
  "ds_pk": {
    "S": "AppSync-delta-sync-post:2019-11-23"
  },
  "ds_sk": {
    "S": "00:44:11.417:81d36bbb-1579-4efe-92b8-2e3f679f628b:2"
  },
  "id": {
    "S": "81d36bbb-1579-4efe-92b8-2e3f679f628b"
  },
  "title": {
    "S": "Actually this is my Second Post"
  }
}
```

Jetzt können wir eine *Delta*-Abfrage simulieren, um Änderungen abzurufen, die aufgetreten sind, als ein Client offline war. Wir verwenden den `startedAt`-Wert, der von unserer *Basis*-Abfrage zurückgegeben wird, um folgende Anfrage zu stellen:

```
query delta {
  syncPosts(limit: 100, lastSync: 1574469602238, nextToken: null) {
    items {
      id
      author
      title
      content
      _version
    }
    startedAt
    nextToken
  }
}
```

Der Rückgabewert dieser *Delta*-Abfrage sieht wie folgt aus:

```
{
  "data": {
    "syncPosts": {
      "items": [
        {
          "id": "81d36bbb-1579-4efe-92b8-2e3f679f628b",
          "author": "Nadia",
          "title": "Actually this is my Second Post",
          "content": "Hello World",
          "_version": 2
        }
      ],
      "startedAt": 1574470400808,
      "nextToken": null
    }
  }
}
```