

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.

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

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.

**Topics**
+ [Erstellen einer einfachen Post-Anwendung mit DynamoDB-Resolvern JavaScript](tutorial-dynamodb-resolvers-js.md)
+ [Verwenden von Resolvern AWS Lambda](tutorial-lambda-resolvers-js.md)
+ [Verwenden von lokalen Resolvern](tutorial-local-resolvers-js.md)
+ [Kombinieren von GraphQL-Resolvern](tutorial-combining-graphql-resolvers-js.md)
+ [Verwenden von OpenSearch Service-Resolvern](tutorial-elasticsearch-resolvers-js.md)
+ [DynamoDB-Transaktionen durchführen](tutorial-dynamodb-transact-js.md)
+ [Verwenden von DynamoDB-Batchoperationen](tutorial-dynamodb-batch-js.md)
+ [Verwendung von HTTP-Resolvern](tutorial-http-resolvers-js.md)
+ [Verwenden von Aurora PostgreSQL mit Daten-API](aurora-serverless-tutorial-js.md)

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

In diesem Tutorial importieren Sie Ihre Amazon DynamoDB-Tabellen in AWS AppSync und verbinden sie, um mithilfe von JavaScript Pipeline-Resolvern, die Sie in Ihrer eigenen Anwendung nutzen können, eine voll funktionsfähige GraphQL-API zu erstellen.

Sie verwenden die AWS AppSync Konsole, um Ihre Amazon DynamoDB DynamoDB-Ressourcen bereitzustellen, Ihre Resolver zu erstellen und sie mit Ihren Datenquellen zu verbinden. Sie werden auch in der Lage sein, über GraphQL-Anweisungen in Ihre Amazon DynamoDB DynamoDB-Datenbank zu lesen und in sie zu schreiben und Echtzeitdaten zu abonnieren.

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

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

**Um eine GraphQL-API zu erstellen in AWS AppSync**

1. Öffnen Sie die AppSync Konsole und wählen Sie **Create API**.

1. Wählen Sie **Von Grund auf neu entwerfen** und **dann Weiter**.

1. Geben Sie Ihrer API `PostTutorialAPI` einen Namen und wählen Sie dann **Weiter**. Gehen Sie zur Bewertungsseite, behalten Sie für die übrigen Optionen die Standardwerte bei und wählen Sie`Create`.

Die AWS AppSync Konsole erstellt eine neue GraphQL-API für Sie. Standardmäßig wird der API-Schlüsselauthentifizierungsmodus verwendet. 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="define-post-api"></a>

Jetzt, wo Sie Ihre GraphQL-API haben, können Sie ein grundlegendes Schema einrichten, das das grundlegende Erstellen, Abrufen und Löschen von Post-Daten ermöglicht.

**Um Daten zu Ihrem Schema hinzuzufügen**

1. Wählen Sie in Ihrer API die Registerkarte **Schema**.

1. Wir werden ein Schema erstellen, das einen `Post` Typ und eine Operation `addPost` zum Hinzufügen und Abrufen von `Post` Objekten definiert. 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 **Save Schema (Schema speichern)**.

## Einrichtung Ihrer Amazon DynamoDB-Tabelle
<a name="configure-dynamodb"></a>

Die AWS AppSync Konsole kann Ihnen helfen, die AWS Ressourcen bereitzustellen, die Sie zum Speichern Ihrer eigenen Ressourcen in einer Amazon DynamoDB-Tabelle benötigen. In diesem Schritt erstellen Sie eine Amazon DynamoDB-Tabelle zum Speichern Ihrer Beiträge. Sie richten auch einen [sekundären Index](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/SecondaryIndexes.html) ein, den wir später verwenden werden.

**So erstellen Sie Ihre Amazon DynamoDB-Tabelle**

1. Wählen Sie auf der **Schemaseite** **Create** Resources aus.

1. Wählen Sie **Bestehenden Typ verwenden** und wählen Sie dann den `Post` Typ aus.

1. Wählen Sie im Abschnitt **Zusätzliche Indizes** die Option **Index hinzufügen** aus.

1. Benennen Sie den Index`author-index`.

1. Stellen Sie `Primary key` das Auf `author` und den `Sort` Schlüssel auf ein`None`.

1. Deaktivieren Sie **GraphQL automatisch generieren**. In diesem Beispiel erstellen wir den Resolver selbst.

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

Sie haben jetzt eine neue Datenquelle namens`PostTable`, die Sie unter **Datenquellen** auf der seitlichen Registerkarte einsehen können. Sie verwenden diese Datenquelle, um Ihre Abfragen und Mutationen mit Ihrer Amazon DynamoDB-Tabelle zu verknüpfen. 

## Einen AddPost-Resolver einrichten (Amazon DynamoDB) PutItem
<a name="configure-addpost"></a>

Da Sie AWS AppSync nun die Amazon DynamoDB-Tabelle kennen, können Sie sie mit einzelnen Abfragen und Mutationen verknüpfen, indem Sie Resolver definieren. Der erste Resolver, den Sie erstellen, ist der verwendete `addPost` Pipeline-Resolver JavaScript, mit dem Sie einen Beitrag in Ihrer Amazon DynamoDB-Tabelle erstellen können. Ein Pipeline-Resolver besteht aus den folgenden Komponenten: 
+ Die Stelle im GraphQL-Schema, an der der Resolver angefügt werden soll. In diesem Fall richten Sie einen Resolver im Feld `createPost` im Typ `Mutation` ein. Dieser Resolver wird aufgerufen, wenn der Aufrufer Mutation aufruft. `{ addPost(...){...} }` 
+ Die Datenquelle für diesen Resolver. In diesem Fall möchten Sie die zuvor definierte DynamoDB-Datenquelle verwenden, damit Sie der `post-table-for-tutorial` DynamoDB-Tabelle Einträge hinzufügen können.
+ Der Request-Handler. Der Request-Handler ist eine Funktion, die die eingehende Anfrage des Aufrufers verarbeitet und sie in Anweisungen AWS AppSync zur Ausführung gegen DynamoDB übersetzt.
+ Der Antworthandler. Die Aufgabe des Response-Handlers besteht darin, die Antwort von DynamoDB zu verarbeiten und sie wieder in etwas zu übersetzen, das 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. 

**Um Ihren Resolver einzurichten**

1. Wählen Sie in Ihrer API den Tab **Schema**.

1. Suchen Sie im Bereich **Resolver** nach dem `addPost` Feld unter dem `Mutation` Typ und wählen Sie dann **Attach** aus.

1. Wählen Sie Ihre Datenquelle und dann **Erstellen** aus.

1. Ersetzen Sie den Code in Ihrem Code-Editor durch diesen Codeausschnitt:

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

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

**Anmerkung**  
In diesem Code verwenden Sie die DynamoDB-Modul-Utils, mit denen Sie auf einfache Weise DynamoDB-Anfragen erstellen können.

AWS AppSync enthält ein Hilfsprogramm zur automatischen ID-Generierung namens`util.autoId()`, das verwendet wird, um eine ID für Ihren neuen Beitrag zu generieren. Wenn Sie keine ID angeben, generiert das Tool sie automatisch für Sie.

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

Weitere Informationen zu den verfügbaren Dienstprogrammen für JavaScript finden Sie unter [JavaScriptLaufzeitfunktionen für Resolver und Funktionen](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference-js.html). 

### Rufen Sie die API auf, um einen Beitrag hinzuzufügen
<a name="call-api-addpost"></a>

Jetzt, da der Resolver konfiguriert wurde, AWS AppSync kann er eine eingehende `addPost` Mutation in einen Amazon DynamoDB DynamoDB-Vorgang `PutItem` übersetzen. Sie können jetzt eine Mutation ausführen, um Inhalte in der Tabelle hinzuzufügen.

**Um den Vorgang auszuführen**

1. Wählen Sie in Ihrer API die Registerkarte **Abfragen** aus.

1. Fügen Sie im Bereich **Abfragen** die folgende Mutation hinzu:

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

1. Wählen Sie „**Ausführen**“ (die orangefarbene Play-Schaltfläche) und anschließend`addPost`. Die Ergebnisse des neu erstellten Beitrags 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
       }
     }
   }
   ```

Die folgende Erklärung zeigt, was passiert ist:

1. AWS AppSync hat eine `addPost` Mutationsanfrage erhalten.

1. AWS AppSync führt den Request-Handler des Resolvers aus. Die `ddb.put` Funktion erstellt eine `PutItem` Anfrage, die wie folgt aussieht:

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

1. AWS AppSync verwendet diesen Wert, um eine Amazon DynamoDB `PutItem` DynamoDB-Anfrage zu generieren und auszuführen.

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

1. Der Antworthandler gibt das Ergebnis sofort zurück (`return ctx.result`).

1. Das Endergebnis ist in der GraphQL-Antwort sichtbar.

## Einrichtung des GetPost-Resolvers (Amazon DynamoDB) GetItem
<a name="configure-getpost"></a>

Jetzt, da Sie der Amazon DynamoDB-Tabelle Daten hinzufügen können, müssen Sie die `getPost` Abfrage so einrichten, dass sie diese Daten aus der Tabelle abrufen kann. Hierzu richten Sie einen weiteren Resolver ein.

**Um Ihren Resolver hinzuzufügen**

1. Wählen Sie in Ihrer API den Tab **Schema**.

1. Suchen Sie im Bereich **Resolver** auf der rechten Seite das `getPost` Feld für den `Query` Typ und wählen Sie dann **Attach** aus.

1. Wählen Sie Ihre Datenquelle und dann **Erstellen** aus.

1. Ersetzen Sie den Code im Code-Editor durch diesen Codeausschnitt:

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

1. Speichern Sie Ihren Resolver.

**Anmerkung**  
In diesem Resolver verwenden wir einen Pfeilfunktionsausdruck für den Antworthandler.

### Rufen Sie die API auf, um einen Beitrag zu erhalten
<a name="call-api-getpost"></a>

Jetzt, da der Resolver eingerichtet wurde, AWS AppSync weiß er, wie eine eingehende `getPost` Anfrage in einen Amazon DynamoDB `GetItem` DynamoDB-Vorgang übersetzt wird. Sie können jetzt eine Abfrage ausführen, um den zuvor erstellten Post abzurufen.

**Um Ihre Abfrage auszuführen**

1. Wählen Sie in Ihrer API den Tab **Abfragen** aus. 

1. Fügen Sie im Bereich **Abfragen** den folgenden Code hinzu und verwenden Sie die ID, die Sie nach der Erstellung Ihres Beitrags kopiert haben:

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

1. Wähle „**Ausführen**“ (die orangefarbene Play-Schaltfläche) und dann`getPost`. Die Ergebnisse des neu erstellten Beitrags sollten im **Ergebnisbereich** rechts neben dem **Abfragebereich angezeigt** werden.

1. Der von Amazon 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
       }
     }
   }
   ```

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 Anforderungsfunktion 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 Anforderungsfunktion könnte beispielsweise wie der folgende Ausschnitt aussehen:

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

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

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

Sie können auch ein [selectionSetList](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html#aws-appsync-resolver-context-reference-info-js)mit verwenden`getPost`, um Folgendes darzustellen: `expression`

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

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

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

## Eine UpdatePost-Mutation erstellen (Amazon DynamoDB) UpdateItem
<a name="configure-updatepost"></a>

Bisher können Sie `Post` Objekte in Amazon DynamoDB erstellen und abrufen. Als Nächstes richten Sie eine neue Mutation ein, um ein Objekt zu aktualisieren. Im Vergleich zu der `addPost` Mutation, bei der alle Felder angegeben werden müssen, können Sie mit dieser Mutation nur die Felder angeben, die Sie ändern möchten. Außerdem wurde ein neues `expectedVersion` Argument eingeführt, mit dem Sie die Version angeben können, die Sie ändern möchten. Sie richten eine Bedingung ein, die sicherstellt, dass Sie die neueste Version des Objekts ändern. Dazu verwenden Sie die `UpdateItem` Amazon DynamoDB DynamoDB-Operation.sc

**Um Ihren Resolver zu aktualisieren**

1. Wählen Sie in Ihrer API den Tab **Schema**.

1. Ä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,
           expectedVersion: Int!
       ): Post
       
       addPost(
           id: ID
           author: String!
           title: String!
           content: String!
           url: String!
       ): Post!
   }
   ```

1. Wählen Sie **Save Schema (Schema speichern)**.

1. Suchen Sie im Bereich **Resolver** auf der rechten Seite nach dem neu erstellten `updatePost` Feld für den `Mutation` Typ und wählen Sie dann **Anhängen** aus. Erstellen Sie Ihren neuen Resolver mithilfe des folgenden Snippets:

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

1. Speichern Sie alle Änderungen, die Sie vorgenommen haben.

Dieser Resolver wird verwendet`ddb.update`, um eine Amazon DynamoDB `UpdateItem` DynamoDB-Anfrage zu erstellen. Anstatt den gesamten Artikel zu schreiben, bitten Sie Amazon DynamoDB lediglich, bestimmte Attribute zu aktualisieren. Dies erfolgt mithilfe von Amazon DynamoDB DynamoDB-Aktualisierungsausdrücken.

Die `ddb.update` Funktion verwendet einen Schlüssel und ein Aktualisierungsobjekt als Argumente. Anschließend überprüfen Sie die Werte der eingehenden Argumente. Wenn ein Wert auf gesetzt ist`null`, verwenden Sie die `remove` DynamoDB-Operation, um zu signalisieren, dass der Wert aus dem DynamoDB-Element entfernt werden soll.

Es gibt auch einen neuen Abschnitt. `condition` Ein Bedingungsausdruck ermöglicht es Ihnen, Amazon DynamoDB mitzuteilen AWS AppSync , ob die Anfrage erfolgreich sein soll, basierend auf dem Zustand des Objekts, das sich bereits in Amazon DynamoDB befand, bevor der Vorgang ausgeführt wird. In diesem Fall möchten Sie, dass die `UpdateItem` Anfrage nur erfolgreich ist, wenn das `version` Feld des Elements, das sich derzeit in Amazon DynamoDB befindet, genau mit dem `expectedVersion` Argument übereinstimmt. Wenn der Artikel aktualisiert wird, möchten wir den Wert von erhöhen. `version` Dies ist mit der Bedienfunktion `increment` einfach zu bewerkstelligen.

Weitere Informationen zu Bedingungsausdrücken finden Sie in der Dokumentation zu [Bedingungsausdrücken](https://docs.aws.amazon.com/appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-condition-expressions).

Weitere Informationen zu der `UpdateItem` Anfrage finden Sie in der [UpdateItem](https://docs.aws.amazon.com/appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-updateitem)Dokumentation und in der Dokumentation zum [DynamoDB-Modul](https://docs.aws.amazon.com/appsync/latest/devguide/built-in-modules-js.html). 

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

### Rufen Sie die API auf, um einen Beitrag zu aktualisieren
<a name="call-api-updatepost"></a>

Versuchen wir, das `Post` Objekt mit dem neuen Resolver zu aktualisieren.

**Um dein Objekt zu aktualisieren**

1. Wählen Sie in Ihrer API den Tab **Abfragen** aus.

1. Fügen Sie im Bereich **Abfragen** die folgende Mutation hinzu. Außerdem müssen Sie das `id` Argument auf den Wert aktualisieren, den Sie sich zuvor notiert haben:

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

1. Wählen Sie **Ausführen** (die orangefarbene Play-Schaltfläche) und dann`updatePost`.

1. Der aktualisierte Beitrag in Amazon DynamoDB sollte im **Ergebnisbereich** rechts neben dem Bereich **Abfragen 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": 2
       }
     }
   }
   ```

In dieser Anfrage haben Sie Amazon DynamoDB gebeten AWS AppSync , nur die `content` Felder `title` und zu aktualisieren. Alle anderen Felder wurden unverändert gelassen (mit Ausnahme der Erhöhung des `version` Felds). Sie haben das `title` Attribut auf einen neuen Wert gesetzt und das `content` Attribut aus dem Beitrag entfernt. Die Felder `author`, `url`, `ups` und `downs` blieben unverändert. Versuchen Sie erneut, die Mutationsanforderung auszuführen, während Sie die Anfrage genau so lassen, wie sie ist. Es wird eine Antwort ähnlich der folgenden angezeigt:

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

Die Anforderung schlägt fehl, weil der Bedingungsausdruck wie folgt ausgewertet wird: `false` 

1. Als Sie die Anfrage zum ersten Mal ausgeführt haben, war der Wert des `version` Felds des Beitrags in Amazon DynamoDB`1`, der `expectedVersion` dem Argument entsprach. Die Anfrage war erfolgreich, was bedeutete, dass das `version` Feld in Amazon DynamoDB auf erhöht wurde. `2`

1. Als Sie die Anfrage zum zweiten Mal ausgeführt haben, war der Wert des `version` Felds des Beitrags in Amazon DynamoDB`2`, der nicht mit dem `expectedVersion` Argument übereinstimmte.

Dieses Muster wird normalerweise als *optimistische Sperre* bezeichnet.

## Stimmenmutationen erstellen (Amazon DynamoDB UpdateItem)
<a name="configure-vote-mutations"></a>

Der `Post` Typ enthält `downs` Felder, um die Aufzeichnung von positiven `ups` und negativen Stimmen zu ermöglichen. Derzeit lässt uns die API jedoch nichts mit ihnen anfangen. Fügen wir eine Mutation hinzu, damit wir die Beiträge positiv und negativ bewerten können.

**Um deine Mutation hinzuzufügen**

1. Wählen Sie in Ihrer API den Tab **Schema**.

1. Ändern Sie im **Schemabereich** den `Mutation` Typ und fügen Sie die Aufzählung hinzu, `DIRECTION` um neue Stimmenmutationen hinzuzufügen:

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

1. Wählen Sie **Save Schema (Schema speichern)**.

1. **Suchen Sie im Bereich **Resolver** auf der rechten Seite nach dem neu erstellten `vote` Feld für den `Mutation` Typ und wählen Sie dann Anhängen aus.** Erstellen Sie einen neuen Resolver, indem Sie den Code erstellen und durch den folgenden Codeausschnitt ersetzen:

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

1. Speichern Sie alle Änderungen, die Sie vorgenommen haben.

### Rufen Sie die API auf, um einen Beitrag positiv oder negativ zu bewerten
<a name="call-api-vote"></a>

Jetzt, da die neuen Resolver eingerichtet wurden, AWS AppSync weiß, wie man eine eingehende `upvotePost` oder `downvote` Mutation in eine Amazon DynamoDB `UpdateItem` DynamoDB-Operation übersetzt. Sie können jetzt Mutationen ausführen, um Upvotes oder Downvotes für den zuvor erstellten Post auszuführen.

**Um Ihre Mutation auszuführen**

1. Wählen Sie in Ihrer API den Tab **Abfragen** aus.

1. Fügen Sie im Bereich **Abfragen** die folgende Mutation hinzu. Außerdem müssen Sie das `id` Argument auf den Wert aktualisieren, den Sie sich zuvor notiert haben:

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

1. Wählen Sie **Ausführen** (die orangefarbene Play-Schaltfläche) und dann`votePost`.

1. Der aktualisierte Beitrag in Amazon DynamoDB sollte im **Ergebnisbereich** rechts neben dem Bereich **Abfragen angezeigt** werden. Das sollte bei Ihnen ähnlich wie im folgenden Bild aussehen:

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

1. Wählen Sie noch ein paar Mal **Ausführen**. Sie sollten sehen, dass die `version` Felder `ups` und bei `1` jeder Ausführung der Abfrage inkrementiert werden.

1. Ändern Sie die Abfrage, um sie mit einem anderen `DIRECTION` aufzurufen.

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

1. Wählen Sie **Ausführen** (die orangefarbene Play-Schaltfläche) und anschließend`votePost`.

   Diesmal sollten die `version` Felder `downs` und bei `1` jeder Ausführung der Abfrage inkrementiert werden.

## Einen DeletePost-Resolver einrichten (Amazon DynamoDB) DeleteItem
<a name="configure-deletepost"></a>

Als Nächstes möchten Sie eine Mutation erstellen, um einen Beitrag zu löschen. Dazu verwenden Sie den `DeleteItem` Amazon DynamoDB DynamoDB-Vorgang.

**Um Ihre Mutation hinzuzufügen**

1. Wählen Sie in Ihrem Schema die Registerkarte **Schema**.

1. Ändern Sie im **Schemabereich** den `Mutation` Typ, um eine neue `deletePost` Mutation hinzuzufügen:

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

1. Dieses Mal haben Sie das `expectedVersion` Feld optional gemacht. Wählen Sie als Nächstes **Schema speichern**.

1. Suchen Sie im Bereich **Resolver** auf der rechten Seite nach dem neu erstellten `delete` Feld im `Mutation` Typ und wählen Sie dann **Anhängen** aus. Erstellen Sie mit dem folgenden Code einen neuen Resolver:

   ```
   import { util } from '@aws-appsync/utils'
   
   import { util } from '@aws-appsync/utils';
   import * as ddb from '@aws-appsync/utils/dynamodb';
   
   export function request(ctx) {
     let condition = null;
     if (ctx.args.expectedVersion) {
       condition = {
         or: [
           { id: { attributeExists: false } },
           { version: { eq: ctx.args.expectedVersion } },
         ],
       };
     }
     return ddb.remove({ key: { id: ctx.args.id }, condition });
   }
   
   export function response(ctx) {
     const { error, result } = ctx;
     if (error) {
       util.appendError(error.message, error.type);
     }
     return result;
   }
   ```
**Anmerkung**  
Das `expectedVersion` Argument ist ein optionales Argument. Wenn der Aufrufer ein `expectedVersion` Argument in der Anfrage festlegt, fügt der Anforderungshandler 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 Amazon DynamoDB genau dem entspricht. `expectedVersion` Wenn es ausgelassen wird, wird kein Bedingungsausdruck für die `DeleteItem`-Anforderung angegeben. Es ist erfolgreich, unabhängig vom Wert von `version` oder ob das Element in Amazon DynamoDB vorhanden ist oder nicht.  
Auch wenn Sie einen Artikel löschen, können Sie den gelöschten Artikel zurücksenden, sofern er nicht bereits gelöscht wurde.

Weitere Informationen zu der `DeleteItem` Anfrage finden Sie in der [DeleteItem](https://docs.aws.amazon.com/appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-deleteitem)Dokumentation.

### Rufen Sie die API auf, um einen Beitrag zu löschen
<a name="call-api-delete"></a>

Jetzt, da der Resolver eingerichtet wurde, AWS AppSync weiß er, wie eine eingehende `delete` Mutation in eine Amazon DynamoDB `DeleteItem` DynamoDB-Operation übersetzt werden kann. Sie können jetzt eine Mutation ausführen, um Inhalte in der Tabelle zu löschen.

**Um Ihre Mutation auszuführen**

1. Wählen Sie in Ihrer API den Tab **Abfragen** aus.

1. Fügen Sie im Bereich **Abfragen** die folgende Mutation hinzu. Außerdem müssen Sie das `id` Argument auf den Wert aktualisieren, den Sie sich zuvor notiert haben:

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

1. Wählen Sie **Ausführen** (die orangefarbene Play-Schaltfläche) und dann`deletePost`.

1. Der Beitrag wurde aus Amazon DynamoDB gelöscht. Beachten Sie, dass der Wert des Elements AWS AppSync zurückgegeben wird, das aus Amazon 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
       }
     }
   }
   ```

1. Der Wert wird nur zurückgegeben, wenn dieser Aufruf von derjenige `deletePost` ist, der ihn tatsächlich aus Amazon DynamoDB löscht. **Wählen Sie erneut Ausführen.**

1. Der Aufruf ist immer noch erfolgreich, aber es wird kein Wert zurückgegeben:

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

1. Versuchen wir nun, einen Beitrag zu löschen, aber diesmal geben wir einen an`expectedValue`. Zunächst müssen Sie einen neuen Beitrag erstellen, da Sie gerade den gelöscht haben, mit dem Sie bisher gearbeitet haben.

1. Fügen Sie im Bereich **Abfragen** die folgende Mutation hinzu:

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

1. Wählen Sie „**Ausführen**“ (die orangefarbene Play-Schaltfläche) und anschließend`addPost`.

1. Die Ergebnisse des neu erstellten Beitrags sollten im **Ergebnisbereich** rechts neben dem **Abfragebereich angezeigt** werden. Notieren Sie den Wert `id` des neu erstellten Objekts, da Sie ihn gleich benötigen werden. 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
       }
     }
   }
   ```

1. Versuchen wir nun, den Beitrag mit einem illegalen Wert für **expectedVersion** zu löschen. Fügen Sie im Bereich **Abfragen** die folgende Mutation hinzu. Außerdem müssen Sie das `id` Argument auf den Wert aktualisieren, den Sie sich zuvor notiert haben:

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

1. Wählen Sie **Ausführen** (die orangefarbene Play-Schaltfläche) und dann`deletePost`. Das folgende Ergebnis wird zurückgegeben:

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

1. Die Anforderung ist fehlgeschlagen, da der Bedingungsausdruck zu `false` ausgewertet wird. Der Wert für `version` des Beitrags in Amazon 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
     }
   }
   ```

1. Wählen Sie **Ausführen** (die orangefarbene Play-Schaltfläche) und dann. `deletePost` 

   Diesmal ist die Anfrage erfolgreich und der Wert, der aus Amazon 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
       }
     }
   }
   ```

1. **Wählen Sie erneut Ausführen.** Der Aufruf ist immer noch erfolgreich, aber diesmal wird kein Wert zurückgegeben, da der Beitrag bereits in Amazon DynamoDB gelöscht wurde.

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

## Einen AllPost-Resolver einrichten (Amazon DynamoDB Scan)
<a name="configure-allpost"></a>

Bisher ist die API nur nützlich, wenn Sie die einzelnen Beiträge kennen, `id` die Sie sich ansehen möchten. Fügen wir jetzt einen neuen Resolver hinzu, der alle Posts in der Tabelle zurückgibt.

**Um deine Mutation hinzuzufügen**

1. Wählen Sie in Ihrer API den Tab **Schema**.

1. Ändern Sie im Bereich **Schema** den `Query` Typ, um eine neue `allPost` Abfrage hinzuzufügen, wie folgt:

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

1. Fügen Sie einen neuen `PaginationPosts`-Typ hinzu:

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

1. Wählen Sie **Save Schema (Schema speichern)**.

1. Suchen Sie im Bereich **Resolver** auf der rechten Seite nach dem neu erstellten `allPost` Feld für den `Query` Typ und wählen Sie dann **Anhängen** aus. Erstellen Sie einen neuen Resolver mit dem folgenden Code:

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

   Der Request-Handler dieses Resolvers erwartet zwei optionale Argumente: 
   + `limit`- Gibt die maximale Anzahl von Elementen an, die in einem einzigen Aufruf zurückgegeben werden sollen.
   + `nextToken`- Wird verwendet, um die nächsten Ergebnisse abzurufen (wir werden später zeigen, woher der Wert für `nextToken` stammt).

1. Speichern Sie alle an Ihrem Resolver vorgenommenen Änderungen.

Weitere Informationen zur `Scan` Anfrage finden Sie in der Referenzdokumentation zum [Scannen](https://docs.aws.amazon.com/appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-scan).

### Rufen Sie die API auf, um alle Beiträge zu scannen
<a name="call-api-scan"></a>

Jetzt, da der Resolver eingerichtet wurde, AWS AppSync weiß er, wie eine eingehende `allPost` Anfrage in einen Amazon DynamoDB `Scan` DynamoDB-Vorgang übersetzt wird. 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.

**Um Daten hinzuzufügen und abzufragen**

1. Wählen Sie in Ihrer API den Tab **Abfragen** aus.

1. Fügen Sie im Bereich **Abfragen** die folgende Mutation hinzu:

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

1. Wählen Sie **Ausführen** (die orangefarbene Play-Schaltfläche). 

1. Scannen wir jetzt die Tabelle so, dass jeweils fünf Ergebnisse zurückgegeben werden. Fügen Sie im Bereich **Abfragen** die folgende Abfrage hinzu:

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

1. Wählen Sie **Ausführen** (die orangefarbene Play-Schaltfläche) und anschließend`allPost`.

   Die ersten fünf Beiträge 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": "<token>"
       }
     }
   }
   ```

1. Sie haben fünf Ergebnisse und ein Ergebnis erhalten`nextToken`, das Sie verwenden können, um die nächsten Ergebnisse zu erhalten. Aktualisieren Sie die `allPost`-Abfrage, um das `nextToken` aus dem vorherigen Ergebnissatz einzuschließen: 

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

1. Wählen Sie **Ausführen** (die orangefarbene Play-Taste) und dann`allPost`.

   Die verbleibenden vier Beiträge sollten im **Ergebnisbereich** rechts neben dem **Abfragebereich angezeigt** werden. `nextToken`In dieser Ergebnisgruppe gibt es keine, da Sie alle neun Beiträge durchgeblättert haben und keiner mehr übrig ist. 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
       }
     }
   }
   ```

## Einen allPostsBy Author-Resolver einrichten (Amazon DynamoDB Query)
<a name="configure-query"></a>

Sie können Amazon DynamoDB nicht nur nach allen Beiträgen durchsuchen, sondern auch Amazon DynamoDB abfragen, um Beiträge abzurufen, die von einem bestimmten Autor erstellt wurden. Die Amazon DynamoDB-Tabelle, die Sie zuvor erstellt haben, hat bereits einen `GlobalSecondaryIndex` Aufruf`author-index`, den Sie mit einer Amazon DynamoDB `Query` DynamoDB-Operation verwenden können, um alle Beiträge abzurufen, die von einem bestimmten Autor erstellt wurden.

**Um Ihre Abfrage hinzuzufügen**

1. Wählen Sie in Ihrer API den Tab **Schema**.

1. Ändern Sie im Bereich **Schema** den `Query` Typ, um eine neue `allPostsByAuthor` Abfrage hinzuzufügen, wie folgt:

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

   Beachten Sie, dass dabei derselbe `PaginatedPosts` Typ verwendet wird, den Sie für die `allPost` Abfrage verwendet haben.

1. Wählen Sie **Save Schema (Schema speichern)**.

1. Suchen Sie im Bereich **Resolver** auf der rechten Seite nach dem neu erstellten `allPostsByAuthor` Feld für den `Query` Typ, und wählen Sie dann **Anhängen** aus. Erstellen Sie mit dem folgenden Codeausschnitt einen Resolver:

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

   Wie der `allPost` Resolver hat auch dieser Resolver zwei optionale Argumente:
   + `limit`- Gibt die maximale Anzahl von Elementen an, die in einem einzigen Aufruf zurückgegeben werden sollen.
   + `nextToken`- Ruft den nächsten Satz von Ergebnissen ab (der Wert für `nextToken` kann aus einem vorherigen Aufruf abgerufen werden).

1. Speichert alle an Ihrem Resolver vorgenommenen Änderungen.

Weitere Informationen zu der `Query` Anfrage finden Sie in der [Query-Referenzdokumentation](https://docs.aws.amazon.com/appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-query).

### Rufen Sie die API auf, um alle Beiträge nach Autor abzufragen
<a name="call-api-query"></a>

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

Vorher sollten wir die Tabelle jedoch mit einigen weiteren Beiträgen füllen, da bisher alle Beiträge denselben Autor haben.

**Um Daten hinzuzufügen und abzufragen**

1. Wählen Sie in Ihrer API den Tab **Abfragen** aus.

1. Fügen Sie im Bereich **Abfragen** die folgende Mutation hinzu:

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

1. Wählen Sie „**Ausführen**“ (die orangefarbene Play-Schaltfläche) und anschließend`addPost`.

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

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

1. Wählen Sie **Ausführen** (die orangefarbene Play-Schaltfläche) und anschließend`allPostsByAuthor`. Alle Beiträge, die von verfasst wurden, `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
       }
     }
   }
   ```

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

1. Fügen Sie im Bereich **Abfragen** die folgende Abfrage hinzu: 

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

1. Wählen Sie **Ausführen** (die orangefarbene Play-Schaltfläche) und anschließend`allPostsByAuthor`. Alle Beiträge, die von verfasst wurden, `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": "<token>"
       }
     }
   }
   ```

1. Aktualisieren Sie das `nextToken`-Argument mit dem Wert, der in der vorherigen Abfrage zurückgegeben wurde:

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

1. Wählen Sie „**Ausführen**“ (die orangefarbene Play-Schaltfläche) und anschließend. `allPostsByAuthor` Die verbleibenden Beiträge, die von verfasst wurden, `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 Sets
<a name="using-sets"></a>

Bis zu diesem Zeitpunkt war der `Post` Typ ein flaches key/value Objekt. Sie können mit Ihrem 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 null 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.

**Um Ihre Daten einzurichten**

1. Wählen Sie in Ihrer API den Tab **Schema**. 

1. Ändern Sie im Bereich **Schema** 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!]
   }
   ```

1. Ändern Sie im **Schemabereich** den `Query` Typ, um eine neue `allPostsByTag` Abfrage hinzuzufügen, wie folgt:

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

1. Ä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!
   }
   ```

1. Wählen Sie **Save Schema (Schema speichern)**.

1. Suchen Sie im Bereich **Resolver** auf der rechten Seite nach dem neu erstellten `allPostsByTag` Feld für den `Query` Typ und wählen Sie dann **Anhängen** aus. Erstellen Sie Ihren Resolver mithilfe des folgenden Snippets:

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

1. Speichern Sie alle Änderungen, die Sie an Ihrem Resolver vorgenommen haben.

1. Gehen Sie nun `addTag` mit dem folgenden Codeausschnitt genauso für das `Mutation` Feld vor:
**Anmerkung**  
Obwohl die DynamoDB-Utils derzeit keine Mengenoperationen unterstützen, können Sie trotzdem mit Sets interagieren, indem Sie die Anfrage selbst erstellen.

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

1. Speichern Sie alle an Ihrem Resolver vorgenommenen Änderungen.

1. Wiederholen Sie dies noch einmal für das `Mutation` Feld `removeTag` mit dem folgenden Codeausschnitt:

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

1. Speichern Sie alle an Ihrem Resolver vorgenommenen Änderungen.

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

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

**Um Tags zu verwenden**

1. Wählen Sie in Ihrer API den Tab **Abfragen** aus.

1. Fügen Sie im Bereich **Abfragen** die folgende Abfrage hinzu:

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

1. Wählen Sie **Ausführen** (die orangefarbene Play-Schaltfläche) und anschließend`allPostsByAuthor`.

1. Alle Beiträge 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
       }
     }
   }
   ```

1. Verwenden wir den mit dem Titel *Der süßeste Hund der Welt*. Nimm es auf`id`, weil du es später benutzen wirst. Versuchen wir nun, ein `dog` Tag hinzuzufügen.

1. Fügen Sie im Bereich **Abfragen** die folgende Mutation hinzu. Außerdem müssen Sie das `id`-Argument mit dem zuvor notierten Wert aktualisieren.

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

1. Wählen Sie „**Ausführen**“ (die orangefarbene Play-Schaltfläche) und anschließend`addTag`. Der Beitrag wurde mit dem neuen Tag aktualisiert:

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

1. Sie können weitere Tags hinzufügen. Aktualisieren Sie die Mutation, um das `tag` Argument wie folgt zu ändern`puppy`:

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

1. Wählen Sie „**Ausführen**“ (die orangefarbene Play-Schaltfläche) und anschließend`addTag`. Der Beitrag wurde mit dem neuen Tag aktualisiert:

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

1. Sie können Tags auch löschen. Fügen Sie im Bereich **Abfragen** die folgende Mutation hinzu. Außerdem müssen Sie das `id` Argument auf den Wert aktualisieren, den Sie sich zuvor notiert haben:

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

1. Wählen Sie **Ausführen** (die orangefarbene Play-Schaltfläche) und dann`removeTag`. Der Post wird aktualisiert und das Tag `puppy` wird gelöscht.

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

1. Du kannst auch nach allen Beiträgen suchen, die ein Schlagwort haben. Fügen Sie im Bereich **Abfragen** die folgende Abfrage hinzu: 

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

1. Wählen Sie **Ausführen** (die orangefarbene Play-Schaltfläche) und anschließend`allPostsByTag`. 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
       }
     }
   }
   ```

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

In diesem Tutorial haben Sie eine API erstellt, mit der Sie `Post` Objekte in DynamoDB mithilfe AWS AppSync von GraphQL bearbeiten können. 

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

**Um die mit Ihrer DynamoDB-Tabelle verknüpfte Rolle zu löschen, wählen Sie Ihre Datenquelle in der Tabelle **Datenquellen** aus und klicken Sie auf Bearbeiten.** Notieren Sie sich den Wert der Rolle unter **Eine bestehende Rolle erstellen oder verwenden**. Gehen Sie zur IAM-Konsole, um die Rolle zu löschen.

Um Ihre DynamoDB-Tabelle zu löschen, klicken Sie in der Datenquellenliste auf den Namen der Tabelle. Dadurch gelangen Sie zur DynamoDB-Konsole, in der Sie die Tabelle löschen können. 

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

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.

## Elektrowerkzeuge für AWS Lambda
<a name="powertools-graphql"></a>

Der Event-Handler Powertools for AWS Lambda GraphQL vereinfacht das Routing und die Verarbeitung von GraphQL-Ereignissen in Lambda-Funktionen. Es ist für Python und Typescript verfügbar. Weitere Informationen zum GraphQL API Event Handler finden Sie in den Powertools. Die AWS Lambda Dokumentation finden Sie in den folgenden Referenzen.
+ [Powertools für den AWS Lambda GraphQL Event Handler (Python)](https://docs.aws.amazon.com/powertools/python/latest/core/event_handler/appsync/)
+ [Powertools für den AWS Lambda GraphQL Event Handler (Typescript)](https://docs.aws.amazon.com/powertools/typescript/latest/features/event-handler/appsync-graphql/) 

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

Das folgende Beispiel zeigt eine Lambda-Funktion, in die geschrieben wurde `Node.js` (Laufzeit: Node.js 18.x), die als Teil einer Blogpost-Anwendung verschiedene Operationen an Blogbeiträgen ausführt. Beachten Sie, dass der Code in einem Dateinamen mit der Erweiterung.mis gespeichert werden sollte.

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

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

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

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

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. 

**Anmerkung**  
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.

## Eine Datenquelle für Lambda konfigurieren
<a name="configure-data-source-for-lamlong-js"></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** aus.

**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. 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-js"></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-js"></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.

Sie werden einen Resolver erstellen, der die Laufzeit AWS AppSync JavaScript (`APPSYNC_JS`) verwendet und mit Ihren Lambda-Funktionen interagiert. Weitere Informationen zum Schreiben von AWS AppSync Resolvern und Funktionen mit JavaScript finden Sie unter [JavaScript Laufzeitfunktionen für Resolver und Funktionen](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference-js.html).

Weitere Informationen zu Lambda-Mapping-Vorlagen finden Sie in der [JavaScript Resolver-Funktionsreferenz für](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-lambda-js.html) 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 im Bereich **Resolver** neben dem Feld die Option **Attach** aus. `getPost(id:ID!): Post` Wählen Sie Ihre Lambda-Datenquelle. Geben Sie als Nächstes den folgenden Code ein:

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

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

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

Dieser Resolver-Code übergibt den Feldnamen, die Liste der Argumente und den Kontext zum Quellobjekt an die Lambda-Funktion, wenn sie diese aufruft. Wählen Sie **Speichern**.

Sie haben nun den ersten Resolver angehängt. Wiederholen Sie diesen Vorgang für die übrigen Felder. 

## Testen Sie Ihre GraphQL-API
<a name="testing-your-graphql-api-js"></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-js"></a>

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

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

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

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

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

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

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

### Aus dem Resolver-Response-Handler
<a name="from-the-resolver-response-handler-js"></a>

Um absichtliche Fehler auszulösen, können Sie die `util.error` Utility-Methode verwenden. Sie benötigt ein Argument an `errorMessage``errorType`, an 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 es im `Post.relatedPosts: [Post]` Resolver-Response-Handler verwendet wird.

```
// the Post.relatedPosts response handler
export function response(ctx) {
    util.error("Failed to fetch relatedPosts", "LambdaFailure", ctx.result)
    return ctx.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-js"></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. 

**Anmerkung**  
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:

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

Der Fehler wird in Ihrem Antworthandler empfangen. Sie können es in der GraphQL-Antwort zurücksenden, indem Sie den Fehler mit an die Antwort anhängen. `util.appendError` Ändern Sie dazu Ihren AWS AppSync Funktionsantwort-Handler wie folgt:

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

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

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

## Anwendungsfall für Fortgeschrittene: Batching
<a name="advanced-use-case-batching-js"></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 {   // 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 {   // 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, aktualisieren wir den Resolver für die `relatedPosts` Batchverarbeitung.

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

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

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

Der Code ändert nun den Vorgang von `Invoke` zu dem `BatchInvoke` Zeitpunkt, an dem das Problem gelöst `fieldName` wird. `relatedPosts` Aktivieren Sie jetzt die Batchverarbeitung für die Funktion im Abschnitt **Batching konfigurieren**. Stellen Sie die maximale Batchgröße auf ein. `5` Wählen Sie **Speichern**.

Mit dieser Änderung erhält die Lambda-Funktion beim Auflösen `relatedPosts` Folgendes als Eingabe:

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

Wenn in der Anfrage 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
]
```

Sie können Ihren Lambda-Code aktualisieren, um die Batchverarbeitung für Folgendes zu handhaben: `relatedPosts`

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

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

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

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

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

Die vorherigen Beispiele zeigen, dass es möglich ist, einen einzelnen Fehler von der Lambda-Funktion zurückzugeben oder einen Fehler von Ihrem Antworthandler 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:

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

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

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

Aktualisieren Sie den `relatedPosts` Resolver-Code:

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

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

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

Der Response-Handler sucht nun nach Fehlern, die von der Lambda-Funktion bei `Invoke` Operationen zurückgegeben wurden, sucht nach Fehlern, die für einzelne Elemente für `BatchInvoke` Operationen zurückgegeben wurden, und überprüft schließlich die`fieldName`. Für`relatedPosts`, die Funktion kehrt zurück`result.data`. Für alle anderen Felder kehrt die Funktion einfach zurück`result`. Sehen Sie sich zum Beispiel die folgende Abfrage an:

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

Diese Abfrage gibt eine GraphQL-Antwort zurück, die der folgenden ähnelt:

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

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

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 \
 --code "<code-goes-here>" \
 --runtime name=APPSYNC_JS,runtimeVersion=1.0.0 \
 --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.

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

AWS AppSync ermöglicht es Ihnen AWS Lambda, unterstützte Datenquellen (Amazon DynamoDB oder Amazon OpenSearch Service) zu verwenden, um verschiedene Operationen durchzuführen. 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 einfach das Ergebnis des Request-Handlers an den Response-Handler **weiter**. Das Feldauflösung verlässt AWS AppSync nicht.

Lokale Resolver sind in einer Vielzahl von Situationen nützlich. Der beliebtest Anwendungsfall ist das Veröffentlichen von Benachrichtigungen ohne Auslösen eines Datenquellenaufrufs. Um diesen Anwendungsfall zu demonstrieren, erstellen wir eine Pub/Sub-Anwendung, in der Benutzer Nachrichten veröffentlichen und abonnieren 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.

## Die Pub/Sub-App erstellen
<a name="create-the-pub-sub-application-js"></a>

Erstellen Sie zunächst eine leere GraphQL-API, indem Sie die Option **Von Grund auf neu entwerfen** wählen und die optionalen Details konfigurieren, wenn Sie Ihre GraphQL-API erstellen.

In unserer Pub/Sub-Anwendung können Kunden Nachrichten abonnieren und veröffentlichen. Jede veröffentlichte Nachricht enthält einen Namen und Daten. Fügen Sie dies dem Schema hinzu:

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

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

type Query {
	getChannel: Channel
}

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

Als Nächstes fügen wir dem `Mutation.publish` Feld einen Resolver hinzu. **Suchen Sie im Bereich **Resolver** neben dem **Schemabereich** den `Mutation` Typ und dann das `publish(...): Channel` Feld und klicken Sie dann auf Anhängen.**

Erstellen Sie eine *None-Datenquelle* und geben Sie ihr *PageDataSource*einen Namen. Hängen Sie sie an Ihren Resolver an.

Fügen Sie Ihre Resolver-Implementierung mithilfe des folgenden Snippets hinzu:

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

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

Stellen Sie sicher, dass Sie den Resolver erstellen und die von Ihnen vorgenommenen Änderungen speichern.

## Nachrichten senden und abonnieren
<a name="send-and-subscribe-to-messages-js"></a>

Damit Kunden Nachrichten empfangen können, müssen sie zunächst einen Posteingang abonniert haben.

Führen Sie im Bereich **Abfragen** das `SubscribeToData` Abonnement aus:

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

 Der Abonnent erhält Nachrichten, wann immer die `publish` Mutation aufgerufen wird, aber nur, wenn die Nachricht an das `channel` Abonnement gesendet wird. Lassen Sie uns das im Bereich **Abfragen** versuchen. Während Ihr Abonnement noch in der Konsole läuft, öffnen Sie eine andere Konsole und führen Sie im Bereich **Abfragen** die folgende Anfrage aus:

**Anmerkung**  
In diesem Beispiel verwenden wir gültige JSON-Zeichenketten.

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

Das Ergebnis sieht etwa wie folgt aus:

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

Wir haben gerade die Verwendung lokaler Resolver demonstriert, indem wir eine Nachricht veröffentlicht und empfangen haben, ohne den AWS AppSync Dienst zu verlassen.

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

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 unabhängig von einem Schema auf einem Resolver konfiguriert wird, haben Sie die Möglichkeit, Ihre GraphQL-Typen über verschiedene Datenquellen aufzulösen oder zu manipulieren, sodass Sie ein Schema kombinieren und anpassen können, um Ihren Anforderungen am besten gerecht zu werden.

Die folgenden Szenarien zeigen, wie Sie Datenquellen in Ihrem Schema mischen und abgleichen können. Bevor Sie beginnen, sollten Sie mit der Konfiguration von Datenquellen und Resolvern für AWS Lambda Amazon DynamoDB und Amazon Service vertraut sein. OpenSearch 

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

Das folgende Schema hat den Typ `Post` mit jeweils drei `Query` `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 hätten Sie insgesamt sechs Resolver, von denen jeder eine Datenquelle benötigt. Eine Möglichkeit, dieses Problem zu lösen, besteht darin, diese mit einer einzigen Amazon DynamoDB-Tabelle namens, zu verbinden`Posts`, in der das `AllPost` Feld einen Scan und das `searchPosts` Feld eine Abfrage ausführt (siehe [JavaScriptResolver-Funktionsreferenz für](https://docs.aws.amazon.com/appsync/latest/devguide/js-resolver-reference-dynamodb.html) DynamoDB). Sie sind jedoch nicht auf Amazon DynamoDB beschränkt; es gibt verschiedene Datenquellen wie Lambda oder OpenSearch Service, um Ihre Geschäftsanforderungen zu erfüllen. 

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

Möglicherweise müssen Sie Ergebnisse aus einer Drittanbieter-Datenbank zurückgeben, die nicht direkt von AWS AppSync Datenquellen unterstützt wird. Möglicherweise müssen Sie auch komplexe Änderungen an den Daten vornehmen, bevor sie an die API-Clients zurückgegeben werden. Dies kann durch eine falsche Formatierung der Datentypen verursacht werden, z. B. durch Zeitstempelunterschiede auf Clients oder durch den Umgang mit Abwärtskompatibilitätsproblemen. In diesem Fall ist es die geeignete Lösung, AWS Lambda Funktionen als Datenquelle mit Ihrer AWS AppSync API zu verbinden. Zur Veranschaulichung: Im folgenden Beispiel manipuliert eine AWS Lambda Funktion Daten, die aus einem Datenspeicher eines Drittanbieters abgerufen wurden:

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

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

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

Hierbei handelt es sich um eine absolut gültige Lambda-Funktion, die dem `AllPost`-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-js"></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. Sie könnten 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 leistungsfähig sein, wenn Sie Ihren Anwendungen erweiterte Suchoperationen wie Stichwörter, unscharfe Wortübereinstimmungen oder sogar Geodatensuchen hinzufügen. Die Übertragung von Daten aus DynamoDB könnte über einen ETL-Prozess erfolgen, oder Sie könnten alternativ mithilfe von Lambda aus DynamoDB streamen.

Informationen zu den ersten Schritten mit diesen speziellen Datenquellen finden Sie in unseren [DynamoDB](https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-dynamodb-resolvers-js.html) - und [Lambda-Tutorials](https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-lambda-resolvers-js.html).

Wenn Sie beispielsweise das Schema aus unserem vorherigen Tutorial verwenden, fügt die folgende Mutation DynamoDB ein Element hinzu:

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

Dadurch werden Daten in DynamoDB geschrieben, das dann Daten über Lambda an Amazon OpenSearch Service streamt, mit dem Sie dann anhand verschiedener Felder nach Beiträgen suchen. 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
    }
}

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

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

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

**Anmerkung**  
Dieser Python-Code ist ein Beispiel und sollte nicht im Produktionscode verwendet werden.

```
import boto3
import requests
from requests_aws4auth import AWS4Auth

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

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

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

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

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

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

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

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 unserer Referenz zu [JavaScript Resolver-Funktionen](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-elasticsearch-js.html) für. OpenSearch

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

Um mit diesem Tutorial beginnen zu können, benötigen Sie eine bestehende OpenSearch Service-Domain. 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 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/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 eine Datenquelle für Service OpenSearch
<a name="configure-data-source-for-es-js"></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 **Datenquelle erstellen** und geben Sie einen benutzerfreundlichen Namen für die Datenquelle ein, z. B. „*oss*“. Wählen Sie dann ** OpenSearch Amazon-Domain** als **Datenquellentyp** und 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 AWS AppSync ihnen die entsprechenden Berechtigungen zuweisen, oder Sie können eine bestehende Rolle auswählen, für die die folgende Inline-Richtlinie gilt:

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 verfügt die OpenSearch Service-Domain über eine eigene **Zugriffsrichtlinie**, die Sie über die Amazon OpenSearch Service-Konsole ändern können. Sie müssen eine Richtlinie ähnlich der folgenden mit den entsprechenden Aktionen und Ressourcen für die OpenSearch Service-Domain hinzufügen. Beachten Sie, dass der **Principal** die AWS AppSync Datenquellenrolle sein wird. Sie finden diese Rolle in der IAM-Konsole, sofern Sie sie von dieser Konsole erstellen lassen.

## Einen Resolver anschließen
<a name="connecting-a-resolver-js"></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:

```
 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 einer Pfadwurzel 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. Suchen Sie im Bereich **Resolver nach** **Attach `searchPosts`** und wählen Sie es aus. Wählen Sie Ihre OpenSearch Service-Datenquelle und speichern Sie den Resolver. Aktualisieren Sie den Code Ihres Resolvers mithilfe des folgenden Snippets:

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

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

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

Dabei wird davon ausgegangen, dass das vorherige Schema Dokumente enthält, die in OpenSearch Service indexiert wurden, unter dem Feld. `post` Wenn Sie Ihre Daten anders strukturieren, müssen Sie sie entsprechend aktualisieren.

## Ihre Suchanfragen ändern
<a name="modifying-your-searches-js"></a>

Der vorherige Resolver-Request-Handler führt eine einfache Abfrage für alle Datensätze durch. Angenommen, Sie möchten nach einem bestimmten Autor suchen. Nehmen wir außerdem an, Sie möchten, dass dieser Autor ein in Ihrer GraphQL-Abfrage definiertes Argument ist. Fügen Sie 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]
}
```

Suchen Sie im Bereich **Resolver nach** **Attach `allPostsByAuthor`** und wählen Sie es aus. Wählen Sie die OpenSearch Service-Datenquelle aus und verwenden Sie den folgenden Code:

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

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

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

Beachten Sie, dass der `body` mit einer Begriffsabfrage für das `author`-Feld ausgefüllt wurde und vom Client als Argument übergeben wurde. Optional können Sie vorab ausgefüllte Informationen verwenden, z. B. Standardtext.

## Daten zum OpenSearch Service hinzufügen
<a name="adding-data-to-es-js"></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), kann dies als Mechanismus dienen, 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** für die `addPost()` Mutation aus. Wählen Sie erneut die OpenSearch Service-Datenquelle aus und verwenden Sie den folgenden Code:

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

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

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

Wie zuvor ist dies ein Beispiel dafür, wie Ihre Daten strukturiert sein könnten. Wenn Sie unterschiedliche Feldnamen oder Indizes haben, müssen Sie `path` und aktualisieren`body`. Dieses Beispiel zeigt auch, wie Sie das`context.arguments`, was auch als geschrieben werden kann`ctx.args`, in Ihrem Request-Handler verwenden.

## Ein einzelnes Dokument wird abgerufen
<a name="retrieving-a-single-document-js"></a>

Wenn Sie schließlich die `getPost(id:ID)` Abfrage in Ihrem 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 **Anhängen**. Wählen Sie erneut die OpenSearch Service-Datenquelle aus und verwenden Sie den folgenden Code:

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

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

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

## Führen Sie Abfragen und Mutationen durch
<a name="tutorial-elasticsearch-resolvers-perform-queries-mutations-js"></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 search {
    searchPosts {
        id
        title
        author
        content
    }
}
```

## Best Practices
<a name="best-practices-js"></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](https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-combining-graphql-resolvers-js.html) 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.

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

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
+ Übergeben einer Liste von Schlüsseln in einer einzigen Abfrage und Rückgabe der Ergebnisse aus einer Tabelle
+ Lesen von Datensätzen aus einer oder mehreren Tabellen in einer einzigen Abfrage
+ In all-or-nothing gewisser Weise Datensätze in Transaktionen in eine oder mehrere Tabellen schreiben
+ Transaktionen werden ausgeführt, wenn einige Bedingungen erfüllt sind

## Berechtigungen
<a name="permissions-js"></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/*"
            ]
        }
    ]
}
```

------

**Anmerkung**  
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 Transaktionsaufrufe für die Tabellen erfolgt im Resolver-Code, den wir weiter unten beschreiben.

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

Der Einfachheit halber verwenden wir die gleiche Datenquelle für alle in diesem Tutorial verwendeten Resolver. 

Wir werden zwei Tabellen namens **SavingAccounts und **checkingAccounts**** haben, beide mit dem `accountNumber` als Partitionsschlüssel und eine **TransactionHistory-Tabelle** mit als Partitionsschlüssel. `transactionId` Sie können die folgenden CLI-Befehle verwenden, um Ihre Tabellen zu erstellen. Stellen Sie sicher, dass Sie es `region` durch Ihre Region ersetzen.

**Mit der CLI**

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

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

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

Erstellen Sie in der AWS AppSync Konsole unter **Datenquellen** eine neue DynamoDB-Datenquelle und geben Sie ihr einen Namen. **TransactTutorial** Wählen Sie **SavingAccounts** als Tabelle aus (obwohl die spezifische Tabelle bei der Verwendung von Transaktionen keine Rolle spielt). Wählen Sie, ob Sie eine neue Rolle und die Datenquelle erstellen möchten. Sie können die Datenquellenkonfiguration überprüfen, um den Namen der generierten Rolle zu sehen. In der IAM-Konsole können Sie eine Inline-Richtlinie hinzufügen, die es der Datenquelle ermöglicht, mit allen Tabellen zu interagieren.

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-js"></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
}
```

### TransactWriteItems - Konten auffüllen
<a name="transactwriteitems-populate-accounts-js"></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**. Wählen Sie die `TransactTutorial` Datenquelle aus und klicken Sie auf **Erstellen**.

Verwenden Sie nun den folgenden Code:

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

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

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

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

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

Speichern Sie den Resolver und navigieren Sie zum Abschnitt **Abfragen** der AWS AppSync Konsole, um die Konten zu fü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-js"></a>

Hängen Sie mit dem folgenden Code einen Resolver an die `transferMoney` Mutation an. Für jede Überweisung benötigen wir einen Erfolgsmodifikator sowohl für das Giro- als auch für das Sparkonto, und wir müssen die Übertragung in Transaktionen nachverfolgen.

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

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

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

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

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

Navigieren Sie nun zum Abschnitt **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 drei 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-js"></a>

Um die Details von Spar- und Girokonten in einer einzigen Transaktionsanfrage abzurufen, fügen wir der `Query.getAccounts` GraphQL-Operation in unserem Schema einen Resolver hinzu. Wählen Sie **Anhängen** und wählen Sie dieselbe `TransactTutorial` Datenquelle aus, die Sie zu Beginn des Tutorials erstellt haben. Verwenden Sie folgenden Code: 

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

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

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

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

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

Speichern Sie den Resolver, und navigieren Sie zu den **Queries (Abfragen)**-Abschnitten der AWS AppSync -Konsole. Führen Sie die folgende Abfrage aus, um die Spar- und Girokonten abzurufen:

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

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

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`. Mithilfe dieser Funktionen können Sie Aufgaben wie die folgenden ausführen: AWS AppSync
+ Übergeben einer Schlüsselliste in einer einzigen Abfrage und Rückgabe der Ergebnisse aus einer Tabelle
+ Lesen von Datensätzen aus einer oder mehreren Tabellen in einer einzigen Abfrage
+ Speichern von Datensätzen in großen Mengen in eine oder mehrere Tabellen
+ Bedingtes Schreiben oder Löschen von Datensätzen in mehreren Tabellen, die möglicherweise eine Beziehung haben

Batch-Operationen AWS AppSync weisen zwei wesentliche Unterschiede zu Vorgängen ohne Batch auf:
+ Die Datenquellenrolle muss über Berechtigungen für alle Tabellen verfügen, auf die der Resolver zugreift.
+ Die Tabellenspezifikation für einen Resolver ist Teil des Anforderungsobjekts.

## Batches aus einzelnen Tabellen
<a name="single-table-batch-js"></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.

Lassen Sie uns zunächst eine neue GraphQL-API erstellen. Wählen Sie in der AWS AppSync Konsole **Create API**, **GraphQL APIs** und **Design from scratch aus**. **Geben Sie Ihrer API einen Namen`BatchTutorial API`, wählen Sie **Weiter** und wählen **Sie im Schritt GraphQL-Ressourcen angeben** die Option **GraphQL-Ressourcen später erstellen** aus und klicken Sie auf Weiter.** Überprüfen Sie Ihre Daten und erstellen Sie die API. Gehen Sie zur **Schema-Seite** und fügen Sie das folgende Schema ein. Beachten Sie dabei, 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]
}
```

Speichern Sie Ihr Schema und wählen Sie oben auf der Seite **Ressourcen erstellen** aus. Wählen Sie **Bestehenden Typ verwenden** und wählen Sie den `Post` Typ aus. Benennen Sie Ihre Tabelle`Posts`. **Stellen Sie sicher, dass der **Primärschlüssel** auf eingestellt ist`id`, deaktivieren Sie die Option **GraphQL automatisch generieren** (Sie geben Ihren eigenen Code an) und wählen Sie Erstellen aus.** AWS AppSync Erstellt zunächst eine neue DynamoDB-Tabelle und eine mit der Tabelle verbundene Datenquelle mit den entsprechenden Rollen. Es gibt jedoch noch einige Berechtigungen, die Sie der Rolle hinzufügen müssen. Gehen Sie zur Seite **Datenquellen** und wählen Sie die neue Datenquelle aus. Unter **Wählen Sie eine vorhandene Rolle** aus werden Sie feststellen, dass automatisch eine Rolle für die Tabelle erstellt wurde. Notieren Sie sich die Rolle (sollte ungefähr so aussehen`appsync-ds-ddb-aaabbbcccddd-Posts`) und wechseln Sie dann zur IAM-Konsole ([https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/)). Wählen Sie in der IAM-Konsole **Rollen** und dann Ihre Rolle aus der Tabelle aus. Klicken Sie in Ihrer Rolle unter **Berechtigungsrichtlinien** auf das "`+`" neben der Richtlinie (sollte einen ähnlichen Namen wie der Rollenname haben). Wenn die Richtlinie angezeigt wird, wählen Sie oben in der zusammenklappbaren Ansicht die Option **Bearbeiten** aus. Sie müssen Ihrer Richtlinie Batch-Berechtigungen hinzufügen, insbesondere `dynamodb:BatchGetItem` und`dynamodb:BatchWriteItem`. Es wird ungefähr so aussehen:

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

****  

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

------

Wählen Sie **Weiter** und dann **Änderungen speichern**. Ihre Richtlinie sollte jetzt die Stapelverarbeitung zulassen.

Gehen Sie zurück in der AWS AppSync Konsole zur **Schemaseite** und wählen Sie neben dem `Mutation.batchAdd` Feld die Option **Anhängen** aus. Erstellen Sie Ihren Resolver mit der `Posts` Tabelle als Datenquelle. Ersetzen Sie im Code-Editor die Handler durch das folgende Snippet. Dieses Snippet nimmt automatisch jedes Element `input PostInput` vom Typ GraphQL und erstellt eine Map, die für den Vorgang benötigt wird: `BatchPutItem`

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

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

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

Navigieren Sie zur Seite „**Abfragen**“ der AWS AppSync Konsole und führen Sie die folgende Mutation aus: `batchAdd`

```
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. Sie können dies überprüfen, indem Sie die DynamoDB-Konsole überprüfen, um nach den in die Tabelle geschriebenen Werten zu suchen. `Posts`

Als Nächstes wiederholen Sie den Vorgang des Anfügens eines Resolvers, jedoch für das `Query.batchGet` Feld, wobei die `Posts` Tabelle als Datenquelle verwendet wird. Ersetzen Sie die Handler durch den folgenden Code. Hierdurch wird automatisch jedes Element im GraphQL `ids:[]`-Typ berücksichtigt und eine Zuordnung erstellt, wie sie für die `BatchGetItem`-Operation erforderlich ist:

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

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

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

**Gehen Sie jetzt zurück zur Abfrageseite 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 für den ein `null` Wert `id` mit dem Wert von zurückgegeben wurde`3`. Das liegt daran, dass es in Ihrer `Posts` Tabelle noch keinen Datensatz mit diesem Wert gab. Beachten Sie außerdem, 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 AWS AppSync in Ihrem Namen ausgeführt wird. Wenn Sie also zu wechseln`batchGet(ids:[1,3,2])`, werden Sie feststellen, 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 abschließend einen weiteren Resolver an das `Mutation.batchDelete` Feld an, indem Sie die `Posts` Tabelle als Datenquelle verwenden. Ersetzen Sie die Handler durch den folgenden Code. Hierdurch wird automatisch jedes Element im GraphQL `ids:[]`-Typ berücksichtigt und eine Zuordnung erstellt, wie sie für die `BatchGetItem`-Operation erforderlich ist:

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

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

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

Gehen Sie jetzt zurück zur **Abfrageseite** 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.

## Batch mit mehreren Tabellen
<a name="multi-table-batch-js"></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 App zur Tiergesundheit, bei der Sensoren den Standort und die Körpertemperatur des Tieres melden. 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.

Wählen Sie in der AWS AppSync Konsole **Create API**, **GraphQL APIs** und **Design from scratch aus**. **Geben Sie Ihrer API einen Namen`MultiBatchTutorial API`, wählen Sie **Weiter** und wählen **Sie im Schritt GraphQL-Ressourcen angeben** die Option **GraphQL-Ressourcen später erstellen** aus und klicken Sie auf Weiter.** Überprüfen Sie Ihre Daten und erstellen Sie die API. Gehen Sie zur **Schema-Seite** und fügen Sie das folgende Schema ein und speichern Sie es:

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

Wir müssen zwei DynamoDB-Tabellen erstellen:
+ `locationReadings`speichert die Messwerte der Sensorposition.
+ `temperatureReadings`speichert die Sensortemperaturwerte.

Beide Tabellen werden dieselbe Primärschlüsselstruktur haben: `sensorId (String)` als Partitionsschlüssel und `timestamp (String)` als Sortierschlüssel.

Wählen Sie oben auf der Seite **Create Resources** aus. Wählen Sie **Bestehenden Typ verwenden** und wählen Sie den `locationReadings` Typ aus. Benennen Sie Ihre Tabelle`locationReadings`. Stellen Sie sicher, dass der **Primärschlüssel** auf `sensorId` und der Sortierschlüssel auf eingestellt sind`timestamp`. **Deaktivieren Sie die Option **GraphQL automatisch generieren** (Sie stellen Ihren eigenen Code bereit) und wählen Sie Erstellen aus.** Wiederholen Sie diesen Vorgang, um den `temperatureReadings` als Typ und Tabellennamen zu `temperatureReadings` verwenden. Verwenden Sie dieselben Tasten wie oben.

Ihre neuen Tabellen werden automatisch generierte Rollen enthalten. Es gibt noch einige Berechtigungen, die Sie diesen Rollen hinzufügen müssen. Gehen Sie zur Seite **Datenquellen** und wählen Sie`locationReadings`. Unter **Wählen Sie eine bestehende Rolle** aus können Sie die Rolle sehen. Notieren Sie sich die Rolle (sollte ungefähr so aussehen`appsync-ds-ddb-aaabbbcccddd-locationReadings`) und wechseln Sie dann zur IAM-Konsole ([https://console.aws.amazon.com/iam/](https://console.aws.amazon.com/iam/)). Wählen Sie in der IAM-Konsole **Rollen** und dann Ihre Rolle aus der Tabelle aus. Klicken Sie in Ihrer Rolle unter **Berechtigungsrichtlinien** auf das "`+`" neben der Richtlinie (sollte einen ähnlichen Namen wie der Rollenname haben). Wenn die Richtlinie angezeigt wird, wählen Sie oben in der zusammenklappbaren Ansicht die Option **Bearbeiten** aus. Sie müssen dieser Richtlinie Berechtigungen hinzufügen. Es wird ungefähr so aussehen:

Wählen Sie **Weiter** und dann **Änderungen speichern**. Wiederholen Sie diesen Vorgang für die `temperatureReadings` Datenquelle mit demselben Richtlinienausschnitt oben.

### BatchPutItem - Aufzeichnen von Sensormesswerten
<a name="batchputitem-recording-sensor-readings-js"></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`. Wir müssen diesem Feld einen Resolver hinzufügen.

Wählen Sie auf der **Schemaseite** der AWS AppSync Konsole neben dem `Mutation.recordReadings` Feld die Option **Anhängen** aus. Erstellen Sie auf dem nächsten Bildschirm Ihren Resolver mit der `locationReadings` Tabelle als Datenquelle.

Nachdem Sie Ihren Resolver erstellt haben, ersetzen Sie die Handler im Editor durch den folgenden Code. Diese `BatchPutItem` Operation ermöglicht es uns, mehrere Tabellen anzugeben: 

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

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

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

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

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.

**Anmerkung**  
Die Verwendung von `utils.appendError()` ähnelt der`util.error()`, mit dem wesentlichen Unterschied, dass sie die Auswertung des Anfrage- oder Antworthandlers nicht unterbricht. Stattdessen signalisiert es, dass ein Fehler mit dem Feld aufgetreten ist, ermöglicht aber die Auswertung des Handlers und damit die Rückgabe von Daten an den Aufrufer. Wir empfehlen die Verwendung, `utils.appendError()` wenn Ihre Anwendung Teilergebnisse zurückgeben muss.

Speichern Sie den Resolver und navigieren Sie in der AWS AppSync Konsole zur Seite **Abfragen**. Wir können jetzt einige Sensorwerte senden.

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 haben zehn Sensorwerte in einer Mutation gesendet, wobei die Messwerte auf zwei Tabellen aufgeteilt wurden. Verwenden Sie die DynamoDB-Konsole, um zu überprüfen, ob die Daten sowohl in der als auch in der `locationReadings` Tabelle angezeigt werden. `temperatureReadings`

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

In ähnlicher Weise müssten wir auch in der Lage sein, Chargen von Sensormesswerten zu löschen. Dazu verwenden wir das GraphQL-Feld `Mutation.deleteReadings`. Wählen Sie auf der **Schemaseite** der AWS AppSync Konsole neben dem `Mutation.deleteReadings` Feld die Option **Anhängen** aus. Erstellen Sie auf dem nächsten Bildschirm Ihren Resolver mit der `locationReadings` Tabelle als Datenquelle.

Nachdem Sie Ihren Resolver erstellt haben, ersetzen Sie die Handler im Code-Editor durch das folgende Snippet. In diesem Resolver verwenden wir einen Hilfsfunktions-Mapper, der die `sensorId` und aus den bereitgestellten Eingaben extrahiert. `timestamp` 

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

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

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

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

Speichern Sie den Resolver und navigieren Sie zur Seite „**Abfragen**“ in der Konsole. AWS AppSync Lassen Sie uns nun ein paar Sensormesswerte löschen.

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

**Anmerkung**  
Im Gegensatz zum `DeleteItem`-Vorgang wird nicht das vollständig gelöschte Element in der Antwort zurückgegeben. Nur der übergebene Schlüssel wird zurückgegeben. Weitere Informationen finden Sie [BatchDeleteItem in der JavaScript Resolver-Funktionsreferenz für DynamoDB](https://docs.aws.amazon.com/appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-batch-delete-item).

Ü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-js"></a>

Eine weitere übliche Operation für unsere App wäre das Abrufen der Messwerte für einen Sensor zu einem bestimmten Zeitpunkt. Fügen wir dazu einen Resolver zum GraphQL-Feld `Query.getReadings` unseres Schemas hinzu. Wählen Sie auf der **Schemaseite** der AWS AppSync Konsole neben dem `Query.getReadings` Feld die Option **Anhängen** aus. Erstellen Sie auf dem nächsten Bildschirm Ihren Resolver mit der `locationReadings` Tabelle als Datenquelle.

Lassen Sie uns den folgenden Code verwenden: 

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

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

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

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

Speichern Sie den Resolver und navigieren Sie zur Seite „**Abfragen**“ in der AWS AppSync Konsole. Lassen Sie uns nun unsere Sensorwerte abrufen.

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-js"></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 von Natur aus anwendungsspezifisch ist, AWS AppSync haben Sie die Möglichkeit, Fehler im Antworthandler zu behandeln. 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. Im Antworthandler können Sie Teilergebnisse auf drei Arten verarbeiten:

1. Überwinden Sie den Aufruffehler, indem Sie einfach Daten zurückgeben.

1. Einen Fehler (using`util.error(...)`) auslösen, indem Sie die Auswertung des Handlers beenden, wodurch keine Daten zurückgegeben werden.

1. Fügt einen Fehler an (using`util.appendError(...)`) und gibt auch Daten zurück.

Lassen Sie uns jeden der drei oben genannten Punkte anhand von DynamoDB-Batchoperationen demonstrieren.

### DynamoDB-Stapelvorgänge
<a name="dynamodb-batch-operations-js"></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 Batch 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.

Das folgende JSON stellt den serialisierten Kontext nach dem DynamoDB-Batchaufruf, aber bevor der Antworthandler aufgerufen wurde, dar:

```
{
  "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 gesetzt. `DynamoDB:ProvisionedThroughputExceededException`
+ Die Ergebnisse werden pro Tabelle unter zugeordnet, `ctx.result.data` obwohl ein Fehler vorliegt.
+ Schlüssel, die nicht verarbeitet wurden, sind unter verfügbar. `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.

**Anmerkung**  
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-js"></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.

Der Code, den wir schreiben, ist vertraut und konzentriert sich nur auf die Ergebnisdaten.

**Antworthandler**

```
export function response(ctx) {
  return 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. Es wird ein Fehler ausgelöst, um die Ausführung des Response-Handlers abzubrechen
<a name="raising-an-error-to-abort-the-response-execution-js"></a>

Wenn Teilausfälle aus Sicht des Clients als vollständige Fehler behandelt werden sollen, können Sie die Ausführung des Antworthandlers abbrechen, um zu verhindern, dass Daten zurückgegeben werden. Das Dienstprogramm `util.error(...)` erzielt genau dieses Verhalten.

**Code des Antworthandlers**

```
export function response(ctx) {
  if (ctx.error) {
    util.error(ctx.error.message, ctx.error.type, null, ctx.result.data.unprocessedKeys);
  }
  return 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-js"></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. Dies `util.appendError(...)` ist die Hilfsmethode, die dieses Verhalten ermöglicht, indem sie es dem Anwendungsdesigner ermöglicht, Fehler an den Kontext anzuhängen, ohne die Auswertung des Antworthandlers zu beeinträchtigen. Nach der Auswertung des Antworthandlers AWS AppSync verarbeitet er alle Kontextfehler, indem er sie an den Fehlerblock der GraphQL-Antwort anhängt.

**Code für den Antworthandler**

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

Wir haben sowohl den Aufruffehler als auch `unprocessedKeys` das Element innerhalb des Fehlerblocks der GraphQL-Antwort weitergeleitet. Das `getReadings` Feld gibt auch Teildaten aus der `locationReadings` Tabelle zurück, wie Sie in der folgenden 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. (...)"
    }
  ]
}
```

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

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.

## 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 Sie Ihre 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 **Create API**.

1. Wählen Sie **GraphQL APIs** und dann **Design from scratch**. Wählen Sie **Weiter** aus.

1. Geben Sie für den API-Namen `UserData` ein. Wählen Sie **Weiter** aus.

1. Wählen Sie `Create GraphQL resources later`. Wählen Sie **Weiter** aus.

1. Überprüfen Sie Ihre Eingaben und wählen Sie **Create API**.

Die AWS AppSync Konsole erstellt mithilfe des API-Schlüsselauthentifizierungsmodus eine neue GraphQL-API für Sie. Sie können die Konsole verwenden, um Ihre GraphQL-API weiter zu konfigurieren und Anfragen auszuführen.

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

Da wir jetzt eine GraphQL-API haben, erstellen Sie ein GraphQL-Schema. Verwenden Sie im **Schema-Editor** in der AWS AppSync Konsole das folgende Snippet:

```
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 Sie Ihre HTTP-Datenquelle
<a name="configure-your-http-data-source"></a>

Gehen Sie wie folgt vor, um die HTTP-Datenquelle zu konfigurieren:

1. Wählen Sie auf der Seite **Datenquellen** in Ihrer AWS AppSync GraphQL-API die Option **Datenquelle erstellen** aus.

1. Geben Sie einen Namen für die Datenquelle ein, z. B. `HTTP_Example`

1. Wählen Sie unter **Datenquellentyp** die Option **HTTP-Endpunkt** aus.

1. Stellen Sie den Endpunkt auf den API-Gateway-Endpunkt ein, der zu Beginn des Tutorials erstellt wurde. **Sie finden Ihren vom Stack generierten Endpunkt, wenn Sie zur Lambda-Konsole navigieren und Ihre Anwendung unter Anwendungen suchen.** In den Einstellungen Ihrer Anwendung sollten Sie einen **API-Endpunkt sehen, der Ihr Endpunkt** sein wird. AWS AppSync Stellen Sie sicher, dass Sie den Phasennamen nicht als Teil des Endpunkts angeben. Wenn Ihr Endpunkt beispielsweise wäre`https://aaabbbcccd.execute-api.us-east-1.amazonaws.com/v1`, würden Sie Folgendes eingeben`https://aaabbbcccd.execute-api.us-east-1.amazonaws.com`.

**Anmerkung**  
Derzeit werden nur öffentliche Endpunkte von AWS AppSync unterstützt.  
Weitere Informationen zu den Zertifizierungsstellen, die vom AWS AppSync Dienst anerkannt werden, finden Sie unter [Zertifizierungsstellen (CA) Recognized by AWS AppSync for HTTPS](http-cert-authorities.md#aws-appsync-http-certificate-authorities) Endpoints.

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

In diesem Schritt verbinden Sie die HTTP-Datenquelle mit den `getUser` `addUser` AND-Abfragen.

So richten Sie den `getUser` Resolver ein:

1. Wählen Sie in Ihrer AWS AppSync GraphQL-API die Registerkarte **Schema**.

1. **Suchen Sie rechts neben dem **Schema-Editor** im Bereich **Resolvers** und unter dem **Abfragetyp** das `getUser` Feld und wählen Sie Anhängen aus.**

1. Behalten Sie den Resolvertyp bei `Unit` und die Laufzeit bei. `APPSYNC_JS`

1. Wählen Sie unter **Datenquellenname** den HTTP-Endpunkt aus, den Sie zuvor erstellt haben.

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

1. Fügen Sie im **Resolver-Code-Editor** das folgende Snippet als Ihren Request-Handler hinzu:

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

1. Fügen Sie das folgende Snippet als Antworthandler hinzu:

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

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

Um den Resolver einzurichten: `addUser`

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

1. **Suchen Sie rechts neben dem **Schema-Editor** im Bereich **Resolver** unter dem **Abfragetyp** das `addUser` Feld und wählen Sie Anhängen aus.**

1. Behalten Sie den Resolvertyp bei `Unit` und die Laufzeit bei. `APPSYNC_JS`

1. Wählen Sie unter **Datenquellenname** den HTTP-Endpunkt aus, den Sie zuvor erstellt haben.

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

1. Fügen Sie im **Resolver-Code-Editor** das folgende Snippet als Ihren Request-Handler hinzu:

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

1. Fügen Sie das folgende Snippet als Antworthandler hinzu:

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

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

   Wenn Sie die `getUser` Abfrage erneut ausführen, sollte sie die folgende Antwort zurückgeben:

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

## Dienste werden aufgerufen AWS
<a name="invoking-aws-services-js"></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 PostgreSQL mit Daten-API in AWS AppSync
<a name="aurora-serverless-tutorial-js"></a>

 

Erfahren Sie, wie Sie Ihre GraphQL-API mit Aurora PostgreSQL-Datenbanken verbinden können. AWS AppSync Diese Integration ermöglicht es Ihnen, skalierbare, datengesteuerte Anwendungen zu erstellen, indem Sie SQL-Abfragen und -Mutationen über GraphQL-Operationen ausführen. AWS AppSync bietet eine Datenquelle für die Ausführung von SQL-Anweisungen für Amazon Aurora Aurora-Cluster, die mit einer Daten-API aktiviert sind. Sie können AWS AppSync Resolver verwenden, um SQL-Anweisungen für die Daten-API mit GraphQL-Abfragen, -Mutationen und Abonnements auszuführen.

Bevor Sie mit diesem Tutorial beginnen, sollten Sie über grundlegende Kenntnisse von AWS Diensten und GraphQL-Konzepten verfügen.

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

**Topics**
+ [Richten Sie Ihre Aurora PostgreSQL-Datenbank ein](#creating-clusters)
+ [Datenbank und Tabelle erstellen](#creating-db-table)
+ [Erstellen eines GraphQL-Schemas](#rds-graphql-schema)
+ [Resolver für RDS](#rds-resolvers)
+ [Löschen Sie Ihren Cluster](#rds-delete-cluster)

## Richten Sie Ihre Aurora PostgreSQL-Datenbank ein
<a name="creating-clusters"></a>

Bevor Sie eine Amazon RDS-Datenquelle hinzufügen AWS AppSync, gehen Sie wie folgt vor.

1. Aktivieren Sie eine Daten-API auf einem Aurora Serverless v2-Cluster.

1. Konfigurieren Sie ein Geheimnis mit AWS Secrets Manager

1. Erstellen Sie den Cluster mit dem folgenden AWS CLI Befehl.

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

Dadurch wird ein ARN für den Cluster zurückgegeben. Nachdem Sie einen Cluster erstellt haben, müssen Sie mit dem folgenden AWS CLI Befehl eine Serverless v2-Instanz 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-postgresql
```

**Anmerkung**  
Es dauert einige Zeit, bis diese Endpunkte aktiviert werden. Sie können ihren Status in der RDS-Konsole auf der Registerkarte **Konnektivität und Sicherheit** für den Cluster überprüfen.

Überprüfen Sie den Clusterstatus mit dem folgenden AWS CLI Befehl.

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

Erstellen Sie ein Secret über die AWS Secrets Manager Konsole oder AWS CLI mit einer Eingabedatei wie der folgenden, 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 appsync-tutorial-rds-secret \
    --secret-string file://creds.json
```

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

## Datenbank und Tabelle erstellen
<a name="creating-db-table"></a>

Erstellen Sie zunächst eine Datenbank mit dem Namen`TESTDB`. In PostgreSQL ist eine Datenbank ein Container, der Tabellen und andere SQL-Objekte enthält. Stellen Sie sicher, dass Ihr Aurora Serverless v2-Cluster korrekt konfiguriert ist, bevor Sie ihn zu Ihrer AWS AppSync API hinzufügen. Erstellen Sie zunächst eine *TESTDB-Datenbank* mit dem folgenden `--sql` Parameter.

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

 Wenn das ohne Fehler läuft, fügen Sie zwei Tabellen mit dem `create table` Befehl hinzu:

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

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

Wenn dies erfolgreich ist, fügen Sie den Cluster als Datenquelle in Ihre API ein.

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

Jetzt, da Ihre Aurora Serverless v2 Data API mit konfigurierten Tabellen läuft, erstellen wir ein GraphQL-Schema. Sie können Ihre API schnell erstellen, indem Sie mit dem API-Erstellungsassistenten Tabellenkonfigurationen aus einer vorhandenen Datenbank importieren.

Um zu beginnen: 

1. Wählen Sie in der AWS AppSync Konsole **Create API** und dann **Start with a Amazon Aurora Cluster** aus. 

1. Geben Sie API-Details wie den **API-Namen** an und wählen Sie dann Ihre Datenbank aus, um die API zu generieren.

1. Wählen Sie Ihre Datenbank aus. Aktualisieren Sie bei Bedarf die Region und wählen Sie dann Ihren Aurora-Cluster und Ihre *TESTDB-Datenbank* aus. 

1. Wählen Sie Ihr Secret und dann **Import**. 

1. Sobald die Tabellen erkannt wurden, aktualisieren Sie die Typnamen. Wechseln Sie `Todos` zu `Todo` und `Tasks` zu`Task`. 

1. Zeigen Sie eine Vorschau des generierten Schemas an, indem Sie **Schemavorschau** wählen. Ihr Schema wird ungefähr so aussehen: 

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

1. 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:ExecuteStatement"
               ],
               "Resource": [
                   "arn:aws:rds:us-east-1:111122223333:cluster:appsync-tutorial",
                   "arn:aws:rds:us-east-1:111122223333:cluster:appsync-tutorial:*"
               ]
           },
           {
               "Effect": "Allow",
               "Action": [
                   "secretsmanager:GetSecretValue"
               ],
               "Resource": [
               "arn:aws:secretsmanager:us-east-1:111122223333:secret:appsync-tutorial-rds-secret",
               "arn:aws:secretsmanager:us-east-1:111122223333:secret:appsync-tutorial-rds-secret:*"
               ]
           }
       ]
   }
   ```

------

   Beachten Sie, dass diese Richtlinie zwei Aussagen enthält, für die Sie Rollenzugriff gewähren. Die erste Ressource ist Ihr Aurora-Cluster und die zweite ist Ihr AWS Secrets Manager ARN. 

   Wählen Sie **Weiter**, überprüfen Sie die Konfigurationsdetails und wählen Sie dann **Create API**. Sie haben jetzt eine voll funktionsfähige API. Sie können die vollständigen Details Ihrer API auf der **Schema-Seite** überprüfen. 

## Resolver für RDS
<a name="rds-resolvers"></a>

Der API-Erstellungsablauf hat automatisch die Resolver für die Interaktion mit unseren Typen erstellt. Wenn Sie sich die **Schema-Seite** ansehen, finden Sie Resolver einiger der folgenden Resolver.
+ Erstellen Sie eine über das Feld`todo`. `Mutation.createTodo`
+ Aktualisieren Sie ein `todo` über das `Mutation.updateTodo` Feld.
+ Löschen Sie ein `todo` über das `Mutation.deleteTodo` Feld.
+ Holen Sie sich eine Single `todo` über das `Query.getTodo` Feld.
+ Liste alle `todos` über das `Query.listTodos` Feld auf.

Sie werden ähnliche Felder und Resolver für den `Task` Typ finden. Schauen wir uns einige der Resolver genauer an. 

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

Wählen Sie im Schema-Editor in der AWS AppSync Konsole auf der rechten Seite die Option neben. `testdb` `createTodo(...): Todo` Der Resolver-Code verwendet die `insert` Funktion aus dem `rds` Modul, um dynamisch eine Insert-Anweisung zu erstellen, die der `todos` Tabelle Daten hinzufügt. Da wir mit Postgres arbeiten, können wir die `returning` Anweisung nutzen, um die eingefügten Daten zurückzuholen.

Aktualisieren Sie den folgenden Resolver, um den `DATE` Feldtyp korrekt anzugeben. `due`

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

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

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

Speichern Sie den Resolver. Der Typhinweis markiert das in unserem Eingabeobjekt `due` korrekt als `DATE` Typ. Dadurch kann die Postgres-Engine den Wert richtig interpretieren. Aktualisieren Sie als Nächstes Ihr Schema, um das `id` aus der `CreateTodo` Eingabe zu entfernen. Da unsere Postgres-Datenbank die generierte ID zurückgeben kann, können Sie sich darauf verlassen, dass sie erstellt und das Ergebnis wie folgt in einer einzigen Anfrage zurückgibt.

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

Nehmen Sie die Änderung vor und aktualisieren Sie Ihr Schema. Gehen Sie zum **Abfrage-Editor**, um der Datenbank wie folgt ein Element hinzuzufügen.

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

Sie erhalten das folgende Ergebnis.

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

### Query.ListToDos
<a name="listtodo"></a>

Wählen Sie im Schema-Editor in der Konsole auf der rechten Seite die Option `testdb` neben. `listTodos(id: ID!): Todo` Der Request-Handler verwendet die Select Utility-Funktion, um eine Anforderung zur Laufzeit dynamisch zu erstellen.

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

Wir möchten `todos` nach dem `due` Datum filtern. Lassen Sie uns den Resolver aktualisieren, in den `due` Werte umgewandelt werden sollen`DATE`. Aktualisieren Sie die Liste der Importe und den Request-Handler wie folgt.

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

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

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

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

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

Gehen Sie im **Query-Editor** wie folgt vor.

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

### mutation.updateTodo
<a name="updatetodo"></a>

Sie können auch ein. `update` `Todo` Lassen Sie uns im **Query-Editor** unser erstes `Todo` Element von aktualisieren `id``1`.

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

Beachten Sie, dass Sie das `id` Element angeben müssen, das Sie aktualisieren möchten. Sie können auch eine Bedingung angeben, um nur ein Element zu aktualisieren, das bestimmte Bedingungen erfüllt. Beispielsweise möchten wir das Element möglicherweise nur bearbeiten, wenn die Beschreibung `edits` wie folgt beginnt.

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

Genau wie wir mit unseren `list` Operationen `create` und umgegangen sind, können wir unseren Resolver so aktualisieren, dass er das `due` Feld in a `DATE` umwandelt. Speichern Sie diese Änderungen `updateTodo` wie folgt.

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

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

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

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

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

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

Versuchen Sie jetzt ein Update mit einer Bedingung:

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

### Mutation.DeleteTodo
<a name="deletetodo"></a>

Du kannst `delete` mit der Mutation ein. `Todo` `deleteTodo` Dies funktioniert wie die `updateTodo` Mutation, und Sie müssen das `id` Element, das Sie löschen möchten, wie folgt angeben.

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

### Schreiben von benutzerdefinierten Abfragen
<a name="writing-custom-queries"></a>

Wir haben die `rds` Modul-Dienstprogramme verwendet, um unsere SQL-Anweisungen zu erstellen. Wir können auch unsere eigene benutzerdefinierte statische Anweisung schreiben, um mit unserer Datenbank zu interagieren. Aktualisieren Sie zunächst das Schema, um das `id` Feld aus der `CreateTask` Eingabe zu entfernen.

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

Erstellen Sie als Nächstes einige Aufgaben. Eine Aufgabe hat `Todo` wie folgt eine Fremdschlüsselbeziehung.

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

Erstellen Sie ein neues Feld Ihres `Query` Typs mit dem folgenden Namen`getTodoAndTasks`.

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

Fügen Sie dem `Todo` Typ wie folgt ein `tasks` Feld hinzu.

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

Speichern Sie das Schema. Wählen Sie im Schema-Editor in der Konsole auf der rechten Seite **Attach Resolver** for `getTodosAndTasks(id: Int!): Todo` aus. Wählen Sie Ihre Amazon RDS-Datenquelle. Aktualisieren Sie Ihren Resolver mit dem folgenden Code.

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

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

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

In diesem Code verwenden wir die `sql` Tag-Vorlage, um eine SQL-Anweisung zu schreiben, an die wir zur Laufzeit sicher einen dynamischen Wert übergeben können. `createPgStatement`kann bis zu zwei SQL-Anfragen gleichzeitig annehmen. Wir verwenden das, um eine Anfrage für uns `todo` und eine weitere für unsere zu senden`tasks`. Sie hätten dies mit einer `JOIN` Anweisung oder einer anderen Methode tun können. Die Idee ist, Ihre eigene SQL-Anweisung schreiben zu können, um Ihre Geschäftslogik zu implementieren. Gehen Sie wie folgt vor, um die **Abfrage** im Query-Editor zu verwenden.

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

## Löschen Sie Ihren Cluster
<a name="rds-delete-cluster"></a>

**Wichtig**  
Das Löschen eines Clusters ist dauerhaft. Überprüfen Sie Ihr Projekt gründlich, bevor Sie diese Aktion ausführen.

Um Ihren Cluster zu löschen:

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