

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

# Tutorial resolver VTL untuk AWS AppSync
<a name="tutorials"></a>

**catatan**  
Kami sekarang terutama mendukung runtime APPSYNC\$1JS dan dokumentasinya. [Harap pertimbangkan untuk menggunakan runtime APPSYNC\$1JS dan panduannya di sini.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

Sumber data dan resolver digunakan oleh AWS AppSync untuk menerjemahkan permintaan GraphQL dan mengambil informasi dari sumber daya Anda. AWS AWS AppSync mendukung penyediaan otomatis dan koneksi dengan tipe sumber data tertentu. AWS AppSync juga mendukung AWS Lambda, Amazon DynamoDB, database relasional (Amazon Aurora Tanpa Server), Layanan OpenSearch Amazon, dan titik akhir HTTP sebagai sumber data. Anda dapat menggunakan GraphQL API dengan sumber daya yang AWS ada atau membangun sumber data dan resolver dari awal. Bagian berikut dimaksudkan untuk menjelaskan beberapa kasus penggunaan GraphQL yang lebih umum dalam bentuk tutorial.

AWS AppSync menggunakan *template pemetaan* yang ditulis dalam Apache Velocity Template Language (VTL) untuk resolver. Untuk informasi selengkapnya tentang penggunaan templat pemetaan, lihat referensi template [pemetaan Resolver](resolver-mapping-template-reference.md#aws-appsync-resolver-mapping-template-reference). Informasi lebih lanjut tentang bekerja dengan VTL tersedia di panduan pemrograman template [pemetaan Resolver](resolver-mapping-template-reference-programming-guide.md#aws-appsync-resolver-mapping-template-reference-programming-guide).

AWS AppSync mendukung penyediaan otomatis tabel DynamoDB dari skema GraphQL seperti yang dijelaskan dalam Penyediaan dari skema (opsional) dan Luncurkan skema sampel. Anda juga dapat mengimpor dari tabel DynamoDB yang ada yang akan membuat skema dan menghubungkan resolver. Ini diuraikan dalam Impor dari Amazon DynamoDB (opsional).

**Topics**
+ [Membuat aplikasi posting sederhana menggunakan DynamoDB resolvers](tutorial-dynamodb-resolvers.md)
+ [Menggunakan AWS Lambda resolver](tutorial-lambda-resolvers.md)
+ [Menggunakan OpenSearch Resolver Layanan](tutorial-elasticsearch-resolvers.md)
+ [Menggunakan resolver lokal](tutorial-local-resolvers.md)
+ [Menggabungkan resolver GraphQL](tutorial-combining-graphql-resolvers.md)
+ [Menggunakan operasi batch DynamoDB](tutorial-dynamodb-batch.md)
+ [Melakukan transaksi DynamoDB](tutorial-dynamodb-transact.md)
+ [Menggunakan resolver HTTP](tutorial-http-resolvers.md)
+ [Menggunakan resolver Aurora Serverless v2](tutorial-rds-resolvers.md)
+ [Menggunakan resolver pipa](tutorial-pipeline-resolvers.md)
+ [Menggunakan operasi Delta Sync pada sumber data berversi](tutorial-delta-sync.md)

# Membuat aplikasi posting sederhana menggunakan DynamoDB resolvers
<a name="tutorial-dynamodb-resolvers"></a>

**catatan**  
Kami sekarang terutama mendukung runtime APPSYNC\$1JS dan dokumentasinya. [Harap pertimbangkan untuk menggunakan runtime APPSYNC\$1JS dan panduannya di sini.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

Tutorial ini menunjukkan bagaimana Anda dapat membawa tabel Amazon DynamoDB Anda sendiri dan menghubungkannya AWS AppSync ke GraphQL API.

Anda dapat mengizinkan AWS AppSync penyediaan sumber daya DynamoDB atas nama Anda. Atau, jika Anda mau, Anda dapat menghubungkan tabel yang ada ke skema GraphQL dengan membuat sumber data dan resolver. Dalam kedua kasus, Anda akan dapat membaca dan menulis ke database DynamoDB Anda melalui pernyataan GraphQL dan berlangganan data real-time.

Ada langkah-langkah konfigurasi khusus yang perlu diselesaikan agar pernyataan GraphQL diterjemahkan ke operasi DynamoDB, dan agar tanggapan diterjemahkan kembali ke GraphQL. Tutorial ini menguraikan proses konfigurasi melalui beberapa skenario dunia nyata dan pola akses data.

## Menyiapkan tabel DynamoDB Anda
<a name="setting-up-your-ddb-tables"></a>

Untuk memulai tutorial ini, pertama-tama Anda harus mengikuti langkah-langkah di bawah ini untuk menyediakan AWS sumber daya.

1. Menyediakan AWS sumber daya menggunakan AWS CloudFormation template berikut di CLI:

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

   Atau, Anda dapat meluncurkan CloudFormation tumpukan berikut di wilayah AS-Barat 2 (Oregon) di akun Anda AWS .

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

   Ini menciptakan yang berikut:
   + Sebuah tabel DynamoDB `AppSyncTutorial-Post` disebut yang akan menyimpan data. `Post`
   + Peran IAM dan kebijakan terkelola IAM terkait AWS AppSync untuk memungkinkan berinteraksi dengan tabel. `Post`

1. Untuk melihat detail selengkapnya tentang tumpukan dan sumber daya yang dibuat, jalankan perintah CLI berikut:

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

1. Untuk menghapus sumber daya nanti, Anda dapat menjalankan yang berikut:

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

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

Untuk membuat GraphQL API di: AWS AppSync

1. Masuk ke Konsol Manajemen AWS dan buka [AppSync konsol](https://console.aws.amazon.com/appsync/).

   1. Di **APIs dasbor**, pilih **Buat API**.

1. Di bawah jendela **Sesuaikan API atau impor dari Amazon DynamoDB**, **pilih** Bangun dari awal.

   1. Pilih **Mulai** di sebelah kanan jendela yang sama.

1. Di bidang **nama API**, atur nama API ke`AWSAppSyncTutorial`.

1. Pilih **Buat**.

 AWS AppSync Konsol membuat API GraphQL baru untuk Anda menggunakan mode autentikasi kunci API. Anda dapat menggunakan konsol untuk mengatur sisa GraphQL API dan menjalankan kueri terhadapnya selama sisa tutorial ini.

## Mendefinisikan API posting dasar
<a name="defining-a-basic-post-api"></a>

Sekarang setelah Anda membuat AWS AppSync GraphQL API, Anda dapat menyiapkan skema dasar yang memungkinkan pembuatan dasar, pengambilan, dan penghapusan data posting.

1. Masuk ke Konsol Manajemen AWS dan buka [AppSync konsol](https://console.aws.amazon.com/appsync/).

   1. Di **APIs dasbor**, pilih API yang baru saja Anda buat.

1. Di **Sidebar**, pilih **Skema**.

   1. Di panel **Skema**, ganti konten dengan kode berikut:

     ```
     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. Pilih **Simpan**.

Skema ini mendefinisikan `Post` jenis dan operasi untuk menambah dan mendapatkan `Post` objek.

## Mengkonfigurasi Sumber Data untuk Tabel DynamoDB
<a name="configuring-the-data-source-for-the-ddb-tables"></a>

Selanjutnya, tautkan kueri dan mutasi yang ditentukan dalam skema ke tabel `AppSyncTutorial-Post` DynamoDB.

Pertama, AWS AppSync perlu menyadari tabel Anda. Anda melakukan ini dengan menyiapkan sumber data di AWS AppSync:

1. Masuk ke Konsol Manajemen AWS dan buka [AppSync konsol](https://console.aws.amazon.com/appsync/).

   1. Di **APIs dasbor**, pilih GraphQL API Anda.

   1. Di **Sidebar**, pilih **Sumber Data**.

1. Pilih **Buat sumber data**.

   1. Untuk **nama sumber data**, masukkan`PostDynamoDBTable`. 

   1. Untuk **tipe sumber data**, pilih tabel **Amazon DynamoDB**.

   1. Untuk **Wilayah**, pilih **US-WEST-2**.

   1. Untuk **nama Tabel**, pilih tabel **AppSyncTutorial-Post DynamoDB**.

   1. Buat peran IAM baru (disarankan) atau pilih peran yang sudah ada yang memiliki izin `lambda:invokeFunction` IAM. Peran yang ada memerlukan kebijakan kepercayaan, seperti yang dijelaskan di bagian [Melampirkan sumber data](attaching-a-data-source.md). 

      Berikut ini adalah contoh kebijakan IAM yang memiliki izin yang diperlukan untuk melakukan operasi pada sumber daya:

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

****  

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

------

1. Pilih **Buat**.

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

**Setelah AWS AppSync mengetahui tabel DynamoDB, Anda dapat menautkannya ke kueri dan mutasi individual dengan mendefinisikan Resolvers.** Resolver pertama yang Anda buat adalah `addPost` resolver, yang memungkinkan Anda untuk membuat posting di tabel DynamoDB. `AppSyncTutorial-Post`

Sebuah resolver memiliki komponen-komponen berikut:
+ Lokasi dalam skema GraphQL untuk melampirkan resolver. Dalam hal ini, Anda menyiapkan resolver di `addPost` bidang pada tipe. `Mutation` Penyelesai ini akan dipanggil saat pemanggil memanggil. `mutation { addPost(...){...} }`
+ Sumber data yang akan digunakan untuk resolver ini. Dalam hal ini, Anda ingin menggunakan sumber `PostDynamoDBTable` data yang Anda tentukan sebelumnya, sehingga Anda dapat menambahkan entri ke dalam tabel `AppSyncTutorial-Post` DynamoDB.
+ Templat pemetaan permintaan . Tujuan dari template pemetaan permintaan adalah untuk mengambil permintaan masuk dari pemanggil dan menerjemahkannya ke dalam instruksi untuk melakukan AWS AppSync terhadap DynamoDB.
+ Templat pemetaan respons. Tugas template pemetaan respons adalah mengambil respons dari DynamoDB dan menerjemahkannya kembali menjadi sesuatu yang diharapkan GraphQL. Ini berguna jika bentuk data di DynamoDB berbeda dengan `Post` tipe di GraphQL, tetapi dalam hal ini mereka memiliki bentuk yang sama, jadi Anda cukup melewatkan data.

Untuk mengatur resolver:

1. Masuk ke Konsol Manajemen AWS dan buka [AppSync konsol](https://console.aws.amazon.com/appsync/).

   1. Di **APIs dasbor**, pilih GraphQL API Anda.

   1. Di **Sidebar**, pilih **Sumber Data**.

1. Pilih **Buat sumber data**.

   1. Untuk **nama sumber data**, masukkan`PostDynamoDBTable`. 

   1. Untuk **tipe sumber data**, pilih tabel **Amazon DynamoDB**.

   1. Untuk **Wilayah**, pilih **US-WEST-2**.

   1. Untuk **nama Tabel**, pilih tabel **AppSyncTutorial-Post DynamoDB**.

   1. Buat peran IAM baru (disarankan) atau pilih peran yang sudah ada yang memiliki izin `lambda:invokeFunction` IAM. Peran yang ada memerlukan kebijakan kepercayaan, seperti yang dijelaskan di bagian [Melampirkan sumber data](attaching-a-data-source.md). 

      Berikut ini adalah contoh kebijakan IAM yang memiliki izin yang diperlukan untuk melakukan operasi pada sumber daya:

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

****  

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

------

1. Pilih **Buat**.

1. Pilih tab **Skema**.

1. ****Di panel **tipe Data** di sebelah kanan, temukan bidang **AddPost** pada tipe Mutasi, lalu pilih Lampirkan.****

1. Di **menu Action**, pilih **Update runtime**, lalu pilih **Unit Resolver (hanya VTL**).

1. Di **Nama sumber data**, pilih **PostDynamoDBTable**.

1. Di **Konfigurasikan templat pemetaan permintaan**, tempel yang berikut ini:

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

   **Catatan:** *Tipe* ditentukan pada semua kunci dan nilai atribut. Misalnya, Anda mengatur `author` bidang ke`{ "S" : "${context.arguments.author}" }`. `S`Bagian menunjukkan kepada AWS AppSync dan DynamoDB bahwa nilai akan menjadi nilai string. Nilai aktual akan diisi dari `author` argumen. Demikian pula, `version` bidang adalah bidang angka karena digunakan `N` untuk tipe. Akhirnya, Anda juga menginisialisasi`ups`, `downs` dan `version` bidang.

   Untuk tutorial ini Anda telah menentukan bahwa tipe `ID!` GraphQL, yang mengindeks item baru yang dimasukkan ke DynamoDB, datang sebagai bagian dari argumen klien. AWS AppSync dilengkapi dengan utilitas untuk pembuatan ID otomatis `$utils.autoId()` yang disebut yang bisa Anda gunakan juga dalam bentuk`"id" : { "S" : "${$utils.autoId()}" }`. Kemudian Anda bisa meninggalkan `id: ID!` keluar dari definisi skema `addPost()` dan itu akan dimasukkan secara otomatis. Anda tidak akan menggunakan teknik ini untuk tutorial ini, tetapi Anda harus menganggapnya sebagai praktik yang baik saat menulis ke tabel DynamoDB.

   Untuk informasi selengkapnya tentang templat pemetaan, lihat dokumentasi referensi [Ikhtisar Templat Pemetaan Resolver](resolver-mapping-template-reference-overview.md#aws-appsync-resolver-mapping-template-reference-overview). Untuk informasi selengkapnya tentang pemetaan GetItem permintaan, lihat dokumentasi [GetItem](aws-appsync-resolver-mapping-template-reference-dynamodb-getitem.md)referensi. Untuk informasi selengkapnya tentang jenis, lihat dokumentasi referensi [Sistem Jenis (Permintaan Pemetaan)](aws-appsync-resolver-mapping-template-reference-dynamodb-typed-values-request.md).

1. Di **Konfigurasikan template pemetaan respons**, tempel yang berikut ini:

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

    **Catatan:** Karena bentuk data dalam `AppSyncTutorial-Post` tabel sama persis dengan bentuk `Post` tipe di GraphQL, template pemetaan respons hanya meneruskan hasilnya secara langsung. Perhatikan juga bahwa semua contoh dalam tutorial ini menggunakan template pemetaan respons yang sama, jadi Anda hanya membuat satu file.

1. Pilih **Simpan**.

### Panggil API untuk Menambahkan Posting
<a name="call-the-api-to-add-a-post"></a>

Sekarang resolver sudah diatur, AWS AppSync dapat menerjemahkan `addPost` mutasi yang masuk ke operasi DynamoDB. PutItem Anda sekarang dapat menjalankan mutasi untuk meletakkan sesuatu di tabel.
+ Pilih tab **Kueri**.
+ Di panel **Kueri**, tempel mutasi berikut:

  ```
  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
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).
+ Hasil posting yang baru dibuat akan muncul di panel hasil di sebelah kanan panel kueri. Itu terlihat serupa dengan yang berikut ini:

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

Inilah yang terjadi:
+ AWS AppSync menerima permintaan `addPost` mutasi.
+ AWS AppSync mengambil permintaan, dan template pemetaan permintaan, dan menghasilkan dokumen pemetaan permintaan. Ini akan terlihat seperti:

  ```
  {
      "version" : "2017-02-28",
      "operation" : "PutItem",
      "key" : {
          "id" : { "S" : "123" }
      },
      "attributeValues" : {
          "author": { "S" : "AUTHORNAME" },
          "title": { "S" : "Our first post!" },
          "content": { "S" : "This is our first post." },
          "url": { "S" : "https://aws.amazon.com/appsync/" },
          "ups" : { "N" : 1 },
          "downs" : { "N" : 0 },
          "version" : { "N" : 1 }
      }
  }
  ```
+ AWS AppSync menggunakan dokumen pemetaan permintaan untuk menghasilkan dan mengeksekusi permintaan DynamoDB`PutItem`.
+ AWS AppSync mengambil hasil `PutItem` permintaan dan mengubahnya kembali ke tipe GraphQL.

  ```
  {
      "id" : "123",
      "author": "AUTHORNAME",
      "title": "Our first post!",
      "content": "This is our first post.",
      "url": "https://aws.amazon.com/appsync/",
      "ups" : 1,
      "downs" : 0,
      "version" : 1
  }
  ```
+ Melewatkannya melalui dokumen pemetaan respons, yang baru saja melewatinya tanpa perubahan.
+ Mengembalikan objek yang baru dibuat dalam respons GraphQL.

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

Sekarang bahwa Anda dapat menambahkan data ke tabel `AppSyncTutorial-Post` DynamoDB, Anda perlu mengatur query sehingga dapat mengambil data dari tabel. `getPost` `AppSyncTutorial-Post` Untuk melakukan ini, Anda mengatur resolver lain.
+ Pilih tab **Skema**.
+ ****Di panel **tipe Data** di sebelah kanan, temukan bidang **GetPost** pada tipe Query, lalu pilih Lampirkan.****
+ Di **menu Action**, pilih **Update runtime**, lalu pilih **Unit Resolver (hanya VTL**).
+ Di **Nama sumber data**, pilih **PostDynamoDBTable**.
+ Di **Konfigurasikan templat pemetaan permintaan**, tempel yang berikut ini:

  ```
  {
      "version" : "2017-02-28",
      "operation" : "GetItem",
      "key" : {
          "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)
      }
  }
  ```
+ Di **Konfigurasikan template pemetaan respons**, tempel yang berikut ini:

  ```
  $utils.toJson($context.result)
  ```
+ Pilih **Simpan**.

### Panggil API untuk Mendapatkan Postingan
<a name="call-the-api-to-get-a-post"></a>

Sekarang resolver telah diatur, AWS AppSync tahu bagaimana menerjemahkan `getPost` query masuk ke operasi DynamoDB. `GetItem` Anda sekarang dapat menjalankan kueri untuk mengambil posting yang Anda buat sebelumnya.
+ Pilih tab **Kueri**.
+ Di panel **Kueri**, tempel berikut ini:

  ```
  query getPost {
    getPost(id:123) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).
+ Posting yang diambil dari DynamoDB akan muncul di panel hasil di sebelah kanan panel kueri. Itu terlihat serupa dengan yang berikut ini:

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

Inilah yang terjadi:
+ AWS AppSync menerima permintaan `getPost` kueri.
+ AWS AppSync mengambil permintaan, dan template pemetaan permintaan, dan menghasilkan dokumen pemetaan permintaan. Ini akan terlihat seperti:

  ```
  {
      "version" : "2017-02-28",
      "operation" : "GetItem",
      "key" : {
          "id" : { "S" : "123" }
      }
  }
  ```
+ AWS AppSync menggunakan dokumen pemetaan permintaan untuk menghasilkan dan mengeksekusi permintaan DynamoDB GetItem .
+ AWS AppSync mengambil hasil `GetItem` permintaan dan mengubahnya kembali ke tipe GraphQL.

  ```
  {
      "id" : "123",
      "author": "AUTHORNAME",
      "title": "Our first post!",
      "content": "This is our first post.",
      "url": "https://aws.amazon.com/appsync/",
      "ups" : 1,
      "downs" : 0,
      "version" : 1
  }
  ```
+ Melewatkannya melalui dokumen pemetaan respons, yang baru saja melewatinya tanpa perubahan.
+ Mengembalikan objek yang diambil dalam respons.

Atau, ambil contoh berikut:

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

Jika `getPost` kueri Anda hanya membutuhkan`id`,, dan `author``title`, Anda dapat mengubah template pemetaan permintaan Anda untuk menggunakan ekspresi proyeksi untuk menentukan hanya atribut yang Anda inginkan dari tabel DynamoDB Anda untuk menghindari transfer data yang tidak perlu dari DynamoDB ke. AWS AppSync Misalnya, template pemetaan permintaan mungkin terlihat seperti cuplikan di bawah ini:

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

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

Sejauh ini Anda dapat membuat dan mengambil `Post` objek di DynamoDB. Selanjutnya, Anda akan mengatur mutasi baru untuk memungkinkan kita untuk memperbarui objek. Anda akan melakukan ini menggunakan operasi UpdateItem DynamoDB.
+ Pilih tab **Skema**.
+ Di panel **Skema**, ubah `Mutation` tipe untuk menambahkan `updatePost` mutasi baru sebagai berikut:

  ```
  type Mutation {
      updatePost(
          id: ID!,
          author: String!,
          title: String!,
          content: String!,
          url: String!
      ): Post
      addPost(
          author: String!
          title: String!
          content: String!
          url: String!
      ): Post!
  }
  ```
+ Pilih **Simpan**.
+ ****Di panel **tipe Data** di sebelah kanan, temukan bidang **UpdatePost** yang baru dibuat pada tipe Mutasi dan kemudian pilih Lampirkan.****
+ Di **menu Action**, pilih **Update runtime**, lalu pilih **Unit Resolver (hanya VTL**).
+ Di **Nama sumber data**, pilih **PostDynamoDBTable**.
+ Di **Konfigurasikan templat pemetaan permintaan**, tempel yang berikut ini:

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

   **Catatan:** Resolver ini menggunakan DynamoDB UpdateItem, yang secara signifikan berbeda dari operasi. PutItem Alih-alih menulis seluruh item, Anda hanya meminta DynamoDB untuk memperbarui atribut tertentu. Ini dilakukan dengan menggunakan DynamoDB Update Expressions. Ekspresi itu sendiri ditentukan dalam `expression` bidang di `update` bagian. Dikatakan untuk mengatur atribut `author``title`,, `content` dan url, dan kemudian menambah `version` bidang. Nilai yang digunakan tidak muncul dalam ekspresi itu sendiri; ekspresi memiliki placeholder yang memiliki nama dimulai dengan titik dua, yang kemudian didefinisikan di `expressionValues` bidang. Akhirnya, DynamoDB memiliki kata-kata cadangan yang tidak dapat muncul di. `expression` Misalnya, `url` adalah kata yang dicadangkan, jadi untuk memperbarui `url` bidang Anda dapat menggunakan placeholder nama dan mendefinisikannya di `expressionNames` bidang.

  Untuk info selengkapnya tentang pemetaan `UpdateItem` permintaan, lihat dokumentasi [UpdateItem](aws-appsync-resolver-mapping-template-reference-dynamodb-updateitem.md)referensi. Untuk informasi selengkapnya tentang cara menulis ekspresi pembaruan, lihat dokumentasi [DynamoDB UpdateExpressions ](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html).
+ Di **Konfigurasikan template pemetaan respons**, tempel yang berikut ini:

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

### Panggil API untuk Memperbarui Posting
<a name="call-the-api-to-update-a-post"></a>

Sekarang resolver telah diatur, AWS AppSync tahu bagaimana menerjemahkan `update` mutasi yang masuk ke operasi DynamoDB. `Update` Anda sekarang dapat menjalankan mutasi untuk memperbarui item yang Anda tulis sebelumnya.
+ Pilih tab **Kueri**.
+ Di panel **Kueri**, tempel mutasi berikut. Anda juga perlu memperbarui `id` argumen ke nilai yang Anda catat sebelumnya.

  ```
  mutation updatePost {
    updatePost(
      id:"123"
      author: "A new author"
      title: "An updated author!"
      content: "Now with updated content!"
      url: "https://aws.amazon.com/appsync/"
    ) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).
+ Posting yang diperbarui di DynamoDB akan muncul di panel hasil di sebelah kanan panel kueri. Itu terlihat serupa dengan yang berikut ini:

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

Dalam contoh ini, `downs` bidang `ups` and tidak dimodifikasi karena template pemetaan permintaan tidak meminta AWS AppSync dan DynamoDB melakukan apa pun dengan bidang tersebut. Juga, `version` bidang bertambah 1 karena Anda meminta AWS AppSync dan DynamoDB untuk menambahkan 1 ke bidang. `version`

## Memodifikasi UpdatePost Resolver (DynamoDB) UpdateItem
<a name="modifying-the-updatepost-resolver-dynamodb-updateitem"></a>

Ini adalah awal yang baik untuk `updatePost` mutasi, tetapi memiliki dua masalah utama:
+ Jika Anda ingin memperbarui hanya satu bidang, Anda harus memperbarui semua bidang.
+ Jika dua orang memodifikasi objek, Anda berpotensi kehilangan informasi.

Untuk mengatasi masalah ini, Anda akan memodifikasi `updatePost` mutasi untuk hanya memodifikasi argumen yang ditentukan dalam permintaan, dan kemudian menambahkan kondisi ke `UpdateItem` operasi.

1. Pilih tab **Skema**.

1. Di panel **Skema**, ubah `updatePost` bidang dalam `Mutation` tipe untuk menghapus tanda seru dari,,, dan `url` argumen `author` `title``content`, pastikan untuk membiarkan bidang apa adanya. `id` Ini akan membuat mereka argumen opsional. Juga, tambahkan `expectedVersion` argumen baru yang diperlukan.

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

1. Pilih **Simpan**.

1. **Di panel **tipe Data** di sebelah kanan, temukan bidang **UpdatePost** pada tipe Mutasi.**

1. Pilih **PostDynamoDBTable**untuk membuka resolver yang ada.

1. Di **Konfigurasikan templat pemetaan permintaan, ubah templat** pemetaan permintaan sebagai berikut:

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

1. Pilih **Simpan**.

Template ini adalah salah satu contoh yang lebih kompleks. Ini menunjukkan kekuatan dan fleksibilitas template pemetaan. Ini mengulang semua argumen, melompati `id` dan`expectedVersion`. Jika argumen diatur ke sesuatu, ia meminta AWS AppSync dan DynamoDB untuk memperbarui atribut itu pada objek di DynamoDB. Jika atribut diatur ke null, ia meminta AWS AppSync dan DynamoDB untuk menghapus atribut itu dari objek post. Jika argumen tidak ditentukan, itu meninggalkan atribut saja. Ini juga menambah `version` bidang.

Juga, ada `condition` bagian baru. Ekspresi kondisi memungkinkan Anda memberi tahu AWS AppSync dan DynamoDB apakah permintaan harus berhasil atau tidak berdasarkan status objek yang sudah ada di DynamoDB sebelum operasi dilakukan. Dalam hal ini, Anda hanya ingin `UpdateItem` permintaan berhasil jika `version` bidang item saat ini di DynamoDB sama persis dengan argumen. `expectedVersion`

Untuk informasi selengkapnya tentang ekspresi kondisi, lihat dokumentasi referensi [Ekspresi Kondisi](aws-appsync-resolver-mapping-template-reference-dynamodb-condition-expressions.md).

### Panggil API untuk Memperbarui Posting
<a name="id1"></a>

Mari kita coba memperbarui `Post` objek dengan resolver baru:
+ Pilih tab **Kueri**.
+ Di panel **Kueri**, tempel mutasi berikut. Anda juga perlu memperbarui `id` argumen ke nilai yang Anda catat sebelumnya.

  ```
  mutation updatePost {
    updatePost(
      id:123
      title: "An empty story"
      content: null
      expectedVersion: 2
    ) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).
+ Posting yang diperbarui di DynamoDB akan muncul di panel hasil di sebelah kanan panel kueri. Itu terlihat serupa dengan yang berikut ini:

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

Dalam permintaan ini, Anda meminta AWS AppSync dan DynamoDB untuk memperbarui bidang dan saja`title`. `content` Itu meninggalkan semua bidang lainnya sendirian (selain menambah `version` bidang). Anda mengatur `title` atribut ke nilai baru, dan menghapus `content` atribut dari posting. Bidang `author``url`,`ups`, dan `downs` ladang dibiarkan tak tersentuh.

Coba jalankan permintaan mutasi lagi, biarkan permintaan persis seperti apa adanya. Anda akan melihat respons yang mirip dengan berikut ini:

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

Permintaan gagal karena ekspresi kondisi dievaluasi menjadi false:
+ Pertama kali Anda menjalankan permintaan, nilai `version` bidang posting di DynamoDB `2` adalah, yang cocok dengan argumen. `expectedVersion` Permintaan berhasil, yang berarti `version` bidang tersebut bertambah di DynamoDB ke. `3`
+ Kedua kalinya Anda menjalankan permintaan, nilai `version` bidang posting di DynamoDB `3` adalah, yang tidak cocok dengan argumen. `expectedVersion`

Pola ini biasanya disebut *penguncian optimis*.

Sebuah fitur dari AWS AppSync DynamoDB resolver adalah bahwa ia mengembalikan nilai saat ini dari objek post di DynamoDB. Anda dapat menemukan ini di `data` bidang di `errors` bagian respons GraphQL. Aplikasi Anda dapat menggunakan informasi ini untuk memutuskan bagaimana hal itu harus dilanjutkan. Dalam hal ini, Anda dapat melihat `version` bidang objek di DynamoDB diatur `3` ke, sehingga Anda bisa memperbarui `expectedVersion` argumen `3` ke dan permintaan akan berhasil lagi.

Untuk informasi selengkapnya tentang menangani kegagalan pemeriksaan kondisi, lihat dokumentasi referensi templat pemetaan [Ekspresi Kondisi](aws-appsync-resolver-mapping-template-reference-dynamodb-condition-expressions.md).

## Buat Mutasi UpVotePost dan DownVotePost (DynamoDB) UpdateItem
<a name="create-upvotepost-and-downvotepost-mutations-ddb-updateitem"></a>

`Post`Jenis memiliki `ups` dan `downs` bidang untuk mengaktifkan rekam suara positif dan suara turun, tetapi sejauh ini API tidak mengizinkan kami melakukan apa pun dengannya. Mari tambahkan beberapa mutasi untuk memungkinkan kita meningkatkan dan menurunkan suara posting.
+ Pilih tab **Skema**.
+ Di panel **Skema**, ubah `Mutation` tipe untuk menambahkan baru `upvotePost` dan `downvotePost` mutasi sebagai berikut:

  ```
  type Mutation {
      upvotePost(id: ID!): Post
      downvotePost(id: ID!): Post
      updatePost(
          id: ID!,
          author: String,
          title: String,
          content: String,
          url: String,
          expectedVersion: Int!
      ): Post
      addPost(
          author: String!,
          title: String!,
          content: String!,
          url: String!
      ): Post!
  }
  ```
+ Pilih **Simpan**.
+ **Di panel **Jenis data** di sebelah kanan, temukan bidang **UpVotePost** yang baru dibuat pada tipe Mutasi, lalu pilih **Lampirkan**.**
+ Di **menu Action**, pilih **Update runtime**, lalu pilih **Unit Resolver (hanya VTL**).
+ Di **Nama sumber data**, pilih **PostDynamoDBTable**.
+ Di **Konfigurasikan templat pemetaan permintaan**, tempel yang berikut ini:

  ```
  {
      "version" : "2017-02-28",
      "operation" : "UpdateItem",
      "key" : {
          "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
      },
      "update" : {
          "expression" : "ADD ups :plusOne, version :plusOne",
          "expressionValues" : {
              ":plusOne" : { "N" : 1 }
          }
      }
  }
  ```
+ Di **Konfigurasikan template pemetaan respons**, tempel yang berikut ini:

  ```
  $utils.toJson($context.result)
  ```
+ Pilih **Simpan**.
+ **Di panel **Jenis data** di sebelah kanan, temukan `downvotePost` bidang yang baru dibuat pada tipe **Mutasi**, lalu pilih Lampirkan.**
+ Di **Nama sumber data**, pilih **PostDynamoDBTable**.
+ Di **Konfigurasikan templat pemetaan permintaan**, tempel yang berikut ini:

  ```
  {
      "version" : "2017-02-28",
      "operation" : "UpdateItem",
      "key" : {
          "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
      },
      "update" : {
          "expression" : "ADD downs :plusOne, version :plusOne",
          "expressionValues" : {
              ":plusOne" : { "N" : 1 }
          }
      }
  }
  ```
+ Di **Konfigurasikan template pemetaan respons**, tempel yang berikut ini:

  ```
  $utils.toJson($context.result)
  ```
+ Pilih **Simpan**.

### Panggil API untuk melakukan upvote dan downvote sebuah Post
<a name="call-the-api-to-upvote-and-downvote-a-post"></a>

Sekarang resolver baru telah diatur, AWS AppSync tahu bagaimana menerjemahkan masuk `upvotePost` atau `downvote` mutasi ke operasi DynamoDB. UpdateItem Anda sekarang dapat menjalankan mutasi untuk upvote atau downvote posting yang Anda buat sebelumnya.
+ Pilih tab **Kueri**.
+ Di panel **Kueri**, tempel mutasi berikut. Anda juga perlu memperbarui `id` argumen ke nilai yang Anda catat sebelumnya.

  ```
  mutation votePost {
    upvotePost(id:123) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).
+ Posting diperbarui di DynamoDB dan akan muncul di panel hasil di sebelah kanan panel kueri. Itu terlihat serupa dengan yang berikut ini:

  ```
  {
    "data": {
      "upvotePost": {
        "id": "123",
        "author": "A new author",
        "title": "An empty story",
        "content": null,
        "url": "https://aws.amazon.com/appsync/",
        "ups": 6,
        "downs": 0,
        "version": 4
      }
    }
  }
  ```
+ Pilih **Jalankan kueri** beberapa kali lagi. Anda akan melihat `version` bidang `ups` dan bertambah 1 setiap kali Anda menjalankan kueri.
+ Ubah kueri untuk memanggil `downvotePost` mutasi sebagai berikut:

  ```
  mutation votePost {
    downvotePost(id:123) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye). Kali ini, Anda akan melihat `version` bidang `downs` dan bertambah 1 setiap kali Anda menjalankan kueri.

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

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

Mutasi berikutnya yang ingin Anda atur adalah menghapus posting. Anda akan melakukan ini menggunakan operasi `DeleteItem` DynamoDB.
+ Pilih tab **Skema**.
+ Di panel **Skema**, ubah `Mutation` tipe untuk menambahkan `deletePost` mutasi baru sebagai berikut:

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

  Kali ini Anda membuat `expectedVersion` bidang opsional, yang dijelaskan nanti ketika Anda menambahkan template pemetaan permintaan.
+ Pilih **Simpan**.
+ **Di panel **Jenis data** di sebelah kanan, temukan bidang **hapus** yang baru dibuat pada Jenis **mutasi**, lalu pilih Lampirkan.**
+ Di **menu Action**, pilih **Update runtime**, lalu pilih **Unit Resolver (hanya VTL**).
+ Di **Nama sumber data**, pilih **PostDynamoDBTable**.
+ Di **Konfigurasikan templat pemetaan permintaan**, tempel yang berikut ini:

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

   **Catatan:** `expectedVersion` Argumen adalah argumen opsional. Jika pemanggil menetapkan `expectedVersion` argumen dalam permintaan, template menambahkan kondisi yang hanya memungkinkan `DeleteItem` permintaan untuk berhasil jika item sudah dihapus atau jika `version` atribut posting di DynamoDB sama persis dengan. `expectedVersion` Jika ditinggalkan, tidak ada ekspresi kondisi yang ditentukan pada `DeleteItem` permintaan. Ini berhasil terlepas dari nilai`version`, atau apakah item ada atau tidak di DynamoDB.
+ Di **Konfigurasikan template pemetaan respons**, tempel yang berikut ini:

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

   **Catatan:** Meskipun Anda menghapus item, Anda dapat mengembalikan item yang telah dihapus, jika belum dihapus.
+ Pilih **Simpan**.

Untuk info selengkapnya tentang pemetaan `DeleteItem` permintaan, lihat dokumentasi [DeleteItem](aws-appsync-resolver-mapping-template-reference-dynamodb-deleteitem.md)referensi.

### Panggil API untuk Menghapus Posting
<a name="call-the-api-to-delete-a-post"></a>

Sekarang resolver telah diatur, AWS AppSync tahu bagaimana menerjemahkan `delete` mutasi yang masuk ke operasi DynamoDB. `DeleteItem` Anda sekarang dapat menjalankan mutasi untuk menghapus sesuatu di tabel.
+ Pilih tab **Kueri**.
+ Di panel **Kueri**, tempel mutasi berikut. Anda juga perlu memperbarui `id` argumen ke nilai yang Anda catat sebelumnya.

  ```
  mutation deletePost {
    deletePost(id:123) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).
+ Posting dihapus dari DynamoDB. Perhatikan bahwa AWS AppSync mengembalikan nilai item yang telah dihapus dari DynamoDB, yang akan muncul di panel hasil di sebelah kanan panel kueri. Itu terlihat serupa dengan yang berikut ini:

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

Nilai hanya dikembalikan jika panggilan ini adalah salah satu yang `deletePost` benar-benar menghapusnya dari DynamoDB.
+ Pilih **Jalankan kueri** lagi.
+ Panggilan masih berhasil, tetapi tidak ada nilai yang dikembalikan.

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

Sekarang mari kita coba menghapus posting, tapi kali ini menentukan. `expectedValue` Pertama-tama, Anda harus membuat posting baru karena Anda baru saja menghapus yang telah Anda kerjakan sejauh ini.
+ Di panel **Kueri**, tempel mutasi berikut:

  ```
  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
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).
+ Hasil posting yang baru dibuat akan muncul di panel hasil di sebelah kanan panel kueri. Catat objek `id` yang baru dibuat karena Anda membutuhkannya hanya dalam beberapa saat. Itu terlihat serupa dengan yang berikut ini:

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

Sekarang mari kita coba menghapus posting itu, tetapi masukkan nilai yang salah untuk`expectedVersion`:
+ Di panel **Kueri**, tempel mutasi berikut. Anda juga perlu memperbarui `id` argumen ke nilai yang Anda catat sebelumnya.

  ```
  mutation deletePost {
    deletePost(
      id:123
      expectedVersion: 9999
    ) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).

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

  Permintaan gagal karena ekspresi kondisi dievaluasi menjadi false: nilai untuk `version` posting di DynamoDB tidak cocok dengan `expectedValue` yang ditentukan dalam argumen. Nilai objek saat ini dikembalikan di `data` bidang di `errors` bagian respons GraphQL.
+ Coba lagi permintaannya, tetapi `expectedVersion` perbaiki:

  ```
  mutation deletePost {
    deletePost(
      id:123
      expectedVersion: 1
    ) {
      id
      author
      title
      content
      url
      ups
      downs
      version
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).
+ Kali ini permintaan berhasil, dan nilai yang dihapus dari DynamoDB dikembalikan:

  ```
  {
    "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
      }
    }
  }
  ```
+ Pilih **Jalankan kueri** lagi.
+ Panggilan masih berhasil, tetapi kali ini tidak ada nilai yang dikembalikan karena posting sudah dihapus di DynamoDB.

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

## Menyiapkan AllPost Resolver (DynamoDB Scan)
<a name="setting-up-the-allpost-resolver-dynamodb-scan"></a>

Sejauh ini API hanya berguna jika Anda mengetahui setiap posting yang ingin Anda lihat. `id` Mari tambahkan resolver baru yang mengembalikan semua posting dalam tabel.
+ Pilih tab **Skema**.
+ Di panel **Skema**, ubah `Query` jenis untuk menambahkan `allPost` kueri baru sebagai berikut:

  ```
  type Query {
      allPost(count: Int, nextToken: String): PaginatedPosts!
      getPost(id: ID): Post
  }
  ```
+ Tambahkan `PaginationPosts` tipe baru:

  ```
  type PaginatedPosts {
      posts: [Post!]!
      nextToken: String
  }
  ```
+ Pilih **Simpan**.
+ ****Di panel **tipe Data** di sebelah kanan, temukan bidang **AllPost** yang baru dibuat pada tipe Query, lalu pilih Lampirkan.****
+ Di **menu Action**, pilih **Update runtime**, lalu pilih **Unit Resolver (hanya VTL**).
+ Di **Nama sumber data**, pilih **PostDynamoDBTable**.
+ Di **Konfigurasikan templat pemetaan permintaan**, tempel yang berikut ini:

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

  Penyelesai ini memiliki dua argumen opsional:`count`, yang menentukan jumlah maksimum item yang akan dikembalikan dalam satu panggilan, dan`nextToken`, yang dapat digunakan untuk mengambil set hasil berikutnya (Anda akan menunjukkan dari mana nilai untuk `nextToken` berasal nanti).
+ Di **Konfigurasikan template pemetaan respons**, tempel yang berikut ini:

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

   **Catatan:** Template pemetaan respons ini berbeda dari yang lainnya sejauh ini. Hasil `allPost` kueri adalah`PaginatedPosts`, yang berisi daftar posting dan token pagination. Bentuk objek ini berbeda dengan apa yang dikembalikan dari AWS AppSync DynamoDB Resolver: daftar posting dipanggil dalam hasil AWS AppSync DynamoDB Resolver, tetapi dipanggil `items` dalam. `posts` `PaginatedPosts`
+ Pilih **Simpan**.

Untuk informasi selengkapnya tentang pemetaan `Scan` permintaan, lihat dokumentasi referensi [Pindai](aws-appsync-resolver-mapping-template-reference-dynamodb-scan.md).

### Panggil API untuk Memindai Semua Posting
<a name="call-the-api-to-scan-all-posts"></a>

Sekarang resolver telah diatur, AWS AppSync tahu bagaimana menerjemahkan `allPost` query masuk ke operasi DynamoDB. `Scan` Anda sekarang dapat memindai tabel untuk mengambil semua posting.

Sebelum Anda dapat mencobanya, Anda perlu mengisi tabel dengan beberapa data karena Anda telah menghapus semua yang telah Anda kerjakan sejauh ini.
+ Pilih tab **Kueri**.
+ Di panel **Kueri**, tempel mutasi berikut:

  ```
  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 }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).

Sekarang, mari kita pindai tabel, mengembalikan lima hasil sekaligus.
+ Di panel **Kueri**, tempel kueri berikut:

  ```
  query allPost {
    allPost(count: 5) {
      posts {
        id
        title
      }
      nextToken
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).
+ Lima posting pertama akan muncul di panel hasil di sebelah kanan panel kueri. Itu terlihat serupa dengan yang berikut ini:

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

Anda mendapat lima hasil dan `nextToken` yang dapat Anda gunakan untuk mendapatkan set hasil berikutnya.
+ Perbarui `allPost` kueri untuk menyertakan `nextToken` dari kumpulan hasil sebelumnya:

  ```
  query allPost {
    allPost(
      count: 5
      nextToken: "eyJ2ZXJzaW9uIjoxLCJ0b2tlbiI6IkFRSUNBSGo4eHR0RG0xWXhUa1F0cEhXMEp1R3B0M1B3eThOSmRvcG9ad2RHYjI3Z0lnRlluNktJRWl6V0ZlR3hJOVJkaStrZUFBQUI1akNDQWVJR0NTcUdTSWIzRFFFSEJxQ0NBZE13Z2dIUEFnRUFNSUlCeUFZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF5cW8yUGFSZThnalFpemRCTUNBUkNBZ2dHWk1JODhUNzhIOFVUZGtpdFM2ZFluSWRyVDg4c2lkN1RjZzB2d1k3VGJTTWpSQ2U3WjY3TkUvU2I1dWNETUdDMmdmMHErSGJSL0pteGRzYzVEYnE1K3BmWEtBdU5jSENJdWNIUkJ0UHBPWVdWdCtsS2U5L1pNcWdocXhrem1RaXI1YnIvQkt6dU5hZmJCdE93NmtoM2Jna1BKM0RjWWhpMFBGbmhMVGg4TUVGSjBCcXg3RTlHR1V5N0tUS0JLZlV3RjFQZ0JRREdrNzFYQnFMK2R1S2IrVGtZZzVYMjFrc3NyQmFVTmNXZmhTeXE0ZUJHSWhqZWQ5c3VKWjBSSTc2ZnVQdlZkR3FLNENjQmxHYXhpekZnK2pKK1FneEU1SXduRTNYYU5TR0I4QUpmamR2bU1wbUk1SEdvWjlMUUswclczbG14RDRtMlBsaTNLaEVlcm9pem5zcmdINFpvcXIrN2ltRDN3QkJNd3BLbGQzNjV5Nnc4ZnMrK2FnbTFVOUlKOFFrOGd2bEgySHFROHZrZXBrMWlLdWRIQ25LaS9USnBlMk9JeEVPazVnRFlzRTRUU09HUlVJTkxYY2MvdW1WVEpBMUthV2hWTlAvdjNlSnlZQUszbWV6N2h5WHVXZ1BkTVBNWERQdTdjVnVRa3EwK3NhbGZOd2wvSUx4bHNyNDVwTEhuVFpyRWZvVlV1bXZ5S2VKY1RUU1lET05hM1NwWEd2UT09In0="
    ) {
      posts {
        id
        author
      }
      nextToken
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).
+ Empat posting yang tersisa akan muncul di panel hasil di sebelah kanan panel kueri. Tidak ada `nextToken` dalam rangkaian hasil ini karena Anda telah membaca semua sembilan posting, dengan tidak ada yang tersisa. Itu terlihat serupa dengan yang berikut ini:

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

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

Selain memindai DynamoDB untuk semua posting, Anda juga dapat meminta DynamoDB untuk mengambil posting yang dibuat oleh penulis tertentu. Tabel DynamoDB yang Anda buat sebelumnya sudah memiliki panggilan `GlobalSecondaryIndex` yang dapat Anda `author-index` gunakan dengan operasi DynamoDB untuk mengambil `Query` semua posting yang dibuat oleh penulis tertentu.
+ Pilih tab **Skema**.
+ Di panel **Skema**, ubah `Query` jenis untuk menambahkan `allPostsByAuthor` kueri baru sebagai berikut:

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

   **Catatan:** Ini menggunakan `PaginatedPosts` jenis yang sama yang Anda gunakan dengan `allPost` kueri.
+ Pilih **Simpan**.
+ Di panel **Jenis data** di sebelah kanan, temukan bidang **allPostsByPenulis** yang baru dibuat pada jenis **kueri**, lalu pilih **Lampirkan**.
+ Di **menu Action**, pilih **Update runtime**, lalu pilih **Unit Resolver (hanya VTL**).
+ Di **Nama sumber data**, pilih **PostDynamoDBTable**.
+ Di **Konfigurasikan templat pemetaan permintaan**, tempel yang berikut ini:

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

  Seperti `allPost` resolver, resolver ini memiliki dua argumen opsional:`count`, yang menentukan jumlah maksimum item yang akan dikembalikan dalam satu panggilan, dan`nextToken`, yang dapat digunakan untuk mengambil set hasil berikutnya (nilai untuk `nextToken` dapat diperoleh dari panggilan sebelumnya).
+ Di **Konfigurasikan template pemetaan respons**, tempel yang berikut ini:

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

   **Catatan:** Ini adalah template pemetaan respons yang sama yang Anda gunakan dalam `allPost` resolver.
+ Pilih **Simpan**.

Untuk informasi selengkapnya tentang pemetaan `Query` permintaan, lihat dokumentasi referensi [kueri](aws-appsync-resolver-mapping-template-reference-dynamodb-query.md).

### Panggil API untuk Menanyakan Semua Postingan oleh Penulis
<a name="call-the-api-to-query-all-posts-by-an-author"></a>

Sekarang resolver telah diatur, AWS AppSync tahu bagaimana menerjemahkan `allPostsByAuthor` mutasi yang masuk ke operasi DynamoDB terhadap indeks. `Query` `author-index` Anda sekarang dapat meminta tabel untuk mengambil semua posting oleh penulis tertentu.

Sebelum Anda melakukan itu, bagaimanapun, mari kita mengisi tabel dengan beberapa posting lagi, karena setiap posting sejauh ini memiliki penulis yang sama.
+ Pilih tab **Kueri**.
+ Di panel **Kueri**, tempel mutasi berikut:

  ```
  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 }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).

Sekarang, mari kita menanyakan tabel, mengembalikan semua posting yang ditulis oleh. `Nadia`
+ Di panel **Kueri**, tempel kueri berikut:

  ```
  query allPostsByAuthor {
    allPostsByAuthor(author: "Nadia") {
      posts {
        id
        title
      }
      nextToken
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).
+ Semua posting yang ditulis oleh akan `Nadia` muncul di panel hasil di sebelah kanan panel query. Itu terlihat serupa dengan yang berikut ini:

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

Pagination bekerja untuk hal yang `Query` sama seperti yang dilakukannya. `Scan` Sebagai contoh, mari kita cari semua posting dengan`AUTHORNAME`, mendapatkan lima sekaligus.
+ Di panel **Kueri**, tempel kueri berikut:

  ```
  query allPostsByAuthor {
    allPostsByAuthor(
      author: "AUTHORNAME"
      count: 5
    ) {
      posts {
        id
        title
      }
      nextToken
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).
+ Semua posting yang ditulis oleh akan `AUTHORNAME` muncul di panel hasil di sebelah kanan panel query. Itu terlihat serupa dengan yang berikut ini:

  ```
  {
    "data": {
      "allPostsByAuthor": {
        "posts": [
          {
            "id": "6",
            "title": "A series of posts, Volume 6"
          },
          {
            "id": "4",
            "title": "A series of posts, Volume 4"
          },
          {
            "id": "2",
            "title": "A series of posts, Volume 2"
          },
          {
            "id": "7",
            "title": "A series of posts, Volume 7"
          },
          {
            "id": "1",
            "title": "A series of posts, Volume 1"
          }
        ],
        "nextToken": "eyJ2ZXJzaW9uIjoxLCJ0b2tlbiI6IkFRSUNBSGo4eHR0RG0xWXhUa1F0cEhXMEp1R3B0M1B3eThOSmRvcG9ad2RHYjI3Z0lnSExqRnVhVUR3ZUhEZ2QzNGJ2QlFuY0FBQUNqekNDQW9zR0NTcUdTSWIzRFFFSEJxQ0NBbnd3Z2dKNEFnRUFNSUlDY1FZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF5Qkg4Yk1obW9LVEFTZHM3SUNBUkNBZ2dKQ3dISzZKNlJuN3pyYUVKY1pWNWxhSkNtZW1KZ0F5N1dhZkc2UEdTNHpNQzJycTkwZHFJTFV6Z25wck9Gd3pMS3VOQ2JvUXc3VDI5eCtnVExIbGg4S3BqbzB1YjZHQ3FwcDhvNDVmMG9JbDlmdS9JdjNXcFNNSXFKTXZ1MEVGVWs1VzJQaW5jZGlUaVRtZFdYWlU1bkV2NkgyRFBRQWZYYlNnSmlHSHFLbmJZTUZZM0FTdmRIL0hQaVZBb1RCMk1YZkg0eGJOVTdEbjZtRFNhb2QwbzdHZHJEWDNtODQ1UXBQUVNyUFhHemY0WDkyajhIdlBCSWE4Smcrb0RxbHozUVQ5N2FXUXdYWWU2S0h4emI1ejRITXdEdXEyRDRkYzhoMi9CbW10MzRMelVGUVIyaExSZGRaZ0xkdzF5cHJZdFZwY3dEc1d4UURBTzdOcjV2ZEp4VVR2TVhmODBRSnp1REhXREpTVlJLdDJwWmlpaXhXeGRwRmNod1BzQ3d2aVBqMGwrcWFFWU1jMXNQbENkVkFGem43VXJrSThWbS8wWHlwR2xZb3BSL2FkV0xVekgrbGMrYno1ZEM2SnVLVXdtY1EyRXlZeDZiS0Izbi9YdUViWGdFeU5PMWZTdE1rRlhyWmpvMVpzdlYyUFRjMzMrdEs0ZDhkNkZrdjh5VVR6WHhJRkxIaVNsOUx6VVdtT3BCaWhrTFBCT09jcXkyOHh1UmkzOEM3UFRqMmN6c3RkOUo1VUY0azBJdUdEbVZzM2xjdWg1SEJjYThIeXM2aEpvOG1HbFpMNWN6R2s5bi8vRE1EbDY3RlJraG5QNFNhSDBpZGI5VFEvMERLeFRBTUdhcWpPaEl5ekVqd2ZDQVJleFdlbldyOGlPVkhScDhGM25WZVdvbFRGK002N0xpdi9XNGJXdDk0VEg3b0laUU5lYmZYKzVOKy9Td25Hb1dyMTlWK0pEb2lIRVFLZ1cwMWVuYjZKUXo5Slh2Tm95ZzF3RnJPVmxGc2xwNlRHa1BlN2Rnd2IrWT0ifQ=="
      }
    }
  }
  ```
+ Perbarui `nextToken` argumen dengan nilai yang dikembalikan dari kueri sebelumnya sebagai berikut:

  ```
  query allPostsByAuthor {
    allPostsByAuthor(
      author: "AUTHORNAME"
      count: 5
      nextToken: "eyJ2ZXJzaW9uIjoxLCJ0b2tlbiI6IkFRSUNBSGo4eHR0RG0xWXhUa1F0cEhXMEp1R3B0M1B3eThOSmRvcG9ad2RHYjI3Z0lnSExqRnVhVUR3ZUhEZ2QzNGJ2QlFuY0FBQUNqekNDQW9zR0NTcUdTSWIzRFFFSEJxQ0NBbnd3Z2dKNEFnRUFNSUlDY1FZSktvWklodmNOQVFjQk1CNEdDV0NHU0FGbEF3UUJMakFSQkF5Qkg4Yk1obW9LVEFTZHM3SUNBUkNBZ2dKQ3dISzZKNlJuN3pyYUVKY1pWNWxhSkNtZW1KZ0F5N1dhZkc2UEdTNHpNQzJycTkwZHFJTFV6Z25wck9Gd3pMS3VOQ2JvUXc3VDI5eCtnVExIbGg4S3BqbzB1YjZHQ3FwcDhvNDVmMG9JbDlmdS9JdjNXcFNNSXFKTXZ1MEVGVWs1VzJQaW5jZGlUaVRtZFdYWlU1bkV2NkgyRFBRQWZYYlNnSmlHSHFLbmJZTUZZM0FTdmRIL0hQaVZBb1RCMk1YZkg0eGJOVTdEbjZtRFNhb2QwbzdHZHJEWDNtODQ1UXBQUVNyUFhHemY0WDkyajhIdlBCSWE4Smcrb0RxbHozUVQ5N2FXUXdYWWU2S0h4emI1ejRITXdEdXEyRDRkYzhoMi9CbW10MzRMelVGUVIyaExSZGRaZ0xkdzF5cHJZdFZwY3dEc1d4UURBTzdOcjV2ZEp4VVR2TVhmODBRSnp1REhXREpTVlJLdDJwWmlpaXhXeGRwRmNod1BzQ3d2aVBqMGwrcWFFWU1jMXNQbENkVkFGem43VXJrSThWbS8wWHlwR2xZb3BSL2FkV0xVekgrbGMrYno1ZEM2SnVLVXdtY1EyRXlZeDZiS0Izbi9YdUViWGdFeU5PMWZTdE1rRlhyWmpvMVpzdlYyUFRjMzMrdEs0ZDhkNkZrdjh5VVR6WHhJRkxIaVNsOUx6VVdtT3BCaWhrTFBCT09jcXkyOHh1UmkzOEM3UFRqMmN6c3RkOUo1VUY0azBJdUdEbVZzM2xjdWg1SEJjYThIeXM2aEpvOG1HbFpMNWN6R2s5bi8vRE1EbDY3RlJraG5QNFNhSDBpZGI5VFEvMERLeFRBTUdhcWpPaEl5ekVqd2ZDQVJleFdlbldyOGlPVkhScDhGM25WZVdvbFRGK002N0xpdi9XNGJXdDk0VEg3b0laUU5lYmZYKzVOKy9Td25Hb1dyMTlWK0pEb2lIRVFLZ1cwMWVuYjZKUXo5Slh2Tm95ZzF3RnJPVmxGc2xwNlRHa1BlN2Rnd2IrWT0ifQ=="
    ) {
      posts {
        id
        title
      }
      nextToken
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).
+ Posting yang tersisa yang ditulis oleh `AUTHORNAME` akan muncul di panel hasil di sebelah kanan panel kueri. Itu terlihat serupa dengan yang berikut ini:

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

## Menggunakan Set
<a name="using-sets"></a>

Sampai saat ini `Post` tipe telah menjadi key/value objek datar. Anda juga dapat memodelkan objek kompleks dengan resolver AWS AppSyncDynamo DB, seperti set, daftar, dan peta.

Mari kita perbarui `Post` jenis untuk menyertakan tag. Sebuah posting dapat memiliki 0 atau lebih tag, yang disimpan di DynamoDB sebagai String Set. Anda juga akan menyiapkan beberapa mutasi untuk menambah dan menghapus tag, dan kueri baru untuk memindai posting dengan tag tertentu.
+ Pilih tab **Skema**.
+ Di panel **Skema**, ubah `Post` jenis untuk menambahkan `tags` bidang baru sebagai berikut:

  ```
  type Post {
    id: ID!
    author: String
    title: String
    content: String
    url: String
    ups: Int!
    downs: Int!
    version: Int!
    tags: [String!]
  }
  ```
+ Di panel **Skema**, ubah `Query` jenis untuk menambahkan `allPostsByTag` kueri baru sebagai berikut:

  ```
  type Query {
    allPostsByTag(tag: String!, count: Int, nextToken: String): PaginatedPosts!
    allPostsByAuthor(author: String!, count: Int, nextToken: String): PaginatedPosts!
    allPost(count: Int, nextToken: String): PaginatedPosts!
    getPost(id: ID): Post
  }
  ```
+ Di panel **Skema**, ubah `Mutation` tipe untuk menambahkan baru `addTag` dan `removeTag` mutasi sebagai berikut:

  ```
  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!
  }
  ```
+ Pilih **Simpan**.
+ Di panel **Tipe data** di sebelah kanan, temukan bidang **allPostsByTag** yang baru dibuat pada Jenis **kueri**, lalu pilih **Lampirkan**.
+ Di **Nama sumber data**, pilih **PostDynamoDBTable**.
+ Di **Konfigurasikan templat pemetaan permintaan**, tempel yang berikut ini:

  ```
  {
      "version" : "2017-02-28",
      "operation" : "Scan",
      "filter": {
        "expression": "contains (tags, :tag)",
          "expressionValues": {
            ":tag": $util.dynamodb.toDynamoDBJson($context.arguments.tag)
          }
      }
      #if( ${context.arguments.count} )
          ,"limit": $util.toJson($context.arguments.count)
      #end
      #if( ${context.arguments.nextToken} )
          ,"nextToken": $util.toJson($context.arguments.nextToken)
      #end
  }
  ```
+ Di **Konfigurasikan template pemetaan respons**, tempel yang berikut ini:

  ```
  {
      "posts": $utils.toJson($context.result.items)
      #if( ${context.result.nextToken} )
          ,"nextToken": $util.toJson($context.result.nextToken)
      #end
  }
  ```
+ Pilih **Simpan**.
+ ****Di panel **Jenis data** di sebelah kanan, temukan bidang **AddTag** yang baru dibuat pada tipe Mutasi, lalu pilih Lampirkan.****
+ Di **Nama sumber data**, pilih **PostDynamoDBTable**.
+ Di **Konfigurasikan templat pemetaan permintaan**, tempel yang berikut ini:

  ```
  {
      "version" : "2017-02-28",
      "operation" : "UpdateItem",
      "key" : {
          "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
      },
      "update" : {
          "expression" : "ADD tags :tags, version :plusOne",
          "expressionValues" : {
              ":tags" : { "SS": [ $util.toJson($context.arguments.tag) ] },
              ":plusOne" : { "N" : 1 }
          }
      }
  }
  ```
+ Di **Konfigurasikan template pemetaan respons**, tempel yang berikut ini:

  ```
  $utils.toJson($context.result)
  ```
+ Pilih **Simpan**.
+ ****Di panel **tipe Data** di sebelah kanan, temukan bidang **RemoveTag yang baru** dibuat pada tipe Mutasi, lalu pilih Lampirkan.****
+ Di **Nama sumber data**, pilih **PostDynamoDBTable**.
+ Di **Konfigurasikan templat pemetaan permintaan**, tempel yang berikut ini:

  ```
  {
      "version" : "2017-02-28",
      "operation" : "UpdateItem",
      "key" : {
          "id" : $util.dynamodb.toDynamoDBJson($context.arguments.id)
      },
      "update" : {
          "expression" : "DELETE tags :tags ADD version :plusOne",
          "expressionValues" : {
              ":tags" : { "SS": [ $util.toJson($context.arguments.tag) ] },
              ":plusOne" : { "N" : 1 }
          }
      }
  }
  ```
+ Di **Konfigurasikan template pemetaan respons**, tempel yang berikut ini:

  ```
  $utils.toJson($context.result)
  ```
+ Pilih **Simpan**.

### Panggil API untuk Bekerja dengan Tag
<a name="call-the-api-to-work-with-tags"></a>

Sekarang setelah Anda menyiapkan resolver, AWS AppSync tahu cara menerjemahkan masuk `addTag``removeTag`, dan permintaan `allPostsByTag` ke DynamoDB dan operasi. `UpdateItem` `Scan`

Untuk mencobanya, mari pilih salah satu posting yang Anda buat sebelumnya. Misalnya, mari kita gunakan posting yang ditulis oleh. `Nadia`
+ Pilih tab **Kueri**.
+ Di panel **Kueri**, tempel kueri berikut:

  ```
  query allPostsByAuthor {
    allPostsByAuthor(
      author: "Nadia"
    ) {
      posts {
        id
        title
      }
      nextToken
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).
+ Semua posting Nadia akan muncul di panel hasil di sebelah kanan panel kueri. Itu terlihat serupa dengan yang berikut ini:

  ```
  {
    "data": {
      "allPostsByAuthor": {
        "posts": [
          {
            "id": "10",
            "title": "The cutest dog in the world"
          },
          {
            "id": "11",
            "title": "Did you known...?"
          }
        ],
        "nextToken": null
      }
    }
  }
  ```
+ Mari kita gunakan yang dengan judul`"The cutest dog in the world"`. Catat `id` karena Anda akan menggunakannya nanti.

Sekarang mari kita coba menambahkan `dog` tag.
+ Di panel **Kueri**, tempel mutasi berikut. Anda juga perlu memperbarui `id` argumen ke nilai yang Anda catat sebelumnya.

  ```
  mutation addTag {
    addTag(id:10 tag: "dog") {
      id
      title
      tags
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).
+ Posting diperbarui dengan tag baru.

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

Anda dapat menambahkan lebih banyak tag sebagai berikut:
+ Perbarui mutasi untuk mengubah `tag` argumen menjadi`puppy`.

  ```
  mutation addTag {
    addTag(id:10 tag: "puppy") {
      id
      title
      tags
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).
+ Posting diperbarui dengan tag baru.

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

Anda juga dapat menghapus tag:
+ Di panel **Kueri**, tempel mutasi berikut. Anda juga perlu memperbarui `id` argumen ke nilai yang Anda catat sebelumnya.

  ```
  mutation removeTag {
    removeTag(id:10 tag: "puppy") {
      id
      title
      tags
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).
+ Posting diperbarui dan `puppy` tag dihapus.

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

Anda juga dapat mencari semua posting yang memiliki tag:
+ Di panel **Kueri**, tempel kueri berikut:

  ```
  query allPostsByTag {
    allPostsByTag(tag: "dog") {
      posts {
        id
        title
        tags
      }
      nextToken
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).
+ Semua posting yang memiliki `dog` tag dikembalikan sebagai berikut:

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

## Menggunakan Daftar dan Peta
<a name="using-lists-and-maps"></a>

Selain menggunakan set DynamoDB, Anda juga dapat menggunakan daftar dan peta DynamoDB untuk memodelkan data kompleks dalam satu objek.

Mari tambahkan kemampuan untuk menambahkan komentar ke posting. Ini akan dimodelkan sebagai daftar objek peta pada objek di DynamoDB. `Post`

 **Catatan:** dalam aplikasi nyata, Anda akan memodelkan komentar di tabel mereka sendiri. Untuk tutorial ini, Anda hanya akan menambahkannya di `Post` tabel.
+ Pilih tab **Skema**.
+ Di panel **Skema**, tambahkan `Comment` tipe baru sebagai berikut:

  ```
  type Comment {
      author: String!
      comment: String!
  }
  ```
+ Di panel **Skema**, ubah `Post` jenis untuk menambahkan `comments` bidang baru sebagai berikut:

  ```
  type Post {
    id: ID!
    author: String
    title: String
    content: String
    url: String
    ups: Int!
    downs: Int!
    version: Int!
    tags: [String!]
    comments: [Comment!]
  }
  ```
+ Di panel **Skema**, ubah `Mutation` tipe untuk menambahkan `addComment` mutasi baru sebagai berikut:

  ```
  type Mutation {
    addComment(id: ID!, author: String!, comment: String!): Post
    addTag(id: ID!, tag: String!): Post
    removeTag(id: ID!, tag: String!): Post
    deletePost(id: ID!, expectedVersion: Int): Post
    upvotePost(id: ID!): Post
    downvotePost(id: ID!): Post
    updatePost(
      id: ID!,
      author: String,
      title: String,
      content: String,
      url: String,
      expectedVersion: Int!
    ): Post
    addPost(
      author: String!,
      title: String!,
      content: String!,
      url: String!
    ): Post!
  }
  ```
+ Pilih **Simpan**.
+ ****Di panel **tipe Data** di sebelah kanan, temukan bidang **AddComment** yang baru dibuat pada tipe Mutasi, lalu pilih Lampirkan.****
+ Di **Nama sumber data**, pilih **PostDynamoDBTable**.
+ Di **Konfigurasikan templat pemetaan permintaan**, tempel yang berikut ini:

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

  Ekspresi pembaruan ini akan menambahkan daftar yang berisi komentar baru kami ke `comments` daftar yang ada. Jika daftar belum ada, itu akan dibuat.
+ Di **Konfigurasikan template pemetaan respons**, tempel yang berikut ini:

  ```
  $utils.toJson($context.result)
  ```
+ Pilih **Simpan**.

### Panggil API untuk Menambahkan Komentar
<a name="call-the-api-to-add-a-comment"></a>

Sekarang setelah Anda menyiapkan resolver, AWS AppSync tahu cara menerjemahkan permintaan masuk `addComment` ke dalam operasi DynamoDB. `UpdateItem`

Mari kita coba dengan menambahkan komentar ke posting yang sama dengan yang Anda tambahkan tag.
+ Pilih tab **Kueri**.
+ Di panel **Kueri**, tempel kueri berikut:

  ```
  mutation addComment {
    addComment(
      id:10
      author: "Steve"
      comment: "Such a cute dog."
    ) {
      id
      comments {
        author
        comment
      }
    }
  }
  ```
+ Pilih **Execute query** (tombol putar oranye).
+ Semua posting Nadia akan muncul di panel hasil di sebelah kanan panel kueri. Itu terlihat serupa dengan yang berikut ini:

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

Jika Anda menjalankan permintaan beberapa kali, beberapa komentar akan ditambahkan ke daftar.

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

Dalam tutorial ini, Anda telah membangun sebuah API yang memungkinkan kita memanipulasi objek Post di AWS AppSync DynamoDB menggunakan dan GraphQL. Untuk informasi selengkapnya, lihat Referensi [Template Pemetaan Resolver](resolver-mapping-template-reference.md#aws-appsync-resolver-mapping-template-reference).

Untuk membersihkan, Anda dapat menghapus AppSync GraphQL API dari konsol.

Untuk menghapus tabel DynamoDB dan peran IAM yang Anda buat untuk tutorial ini, Anda dapat menjalankan yang berikut ini untuk menghapus `AWSAppSyncTutorialForAmazonDynamoDB` tumpukan, atau mengunjungi CloudFormation konsol dan menghapus tumpukan:

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

# Menggunakan AWS Lambda resolver di AWS AppSync
<a name="tutorial-lambda-resolvers"></a>

**catatan**  
Kami sekarang terutama mendukung runtime APPSYNC\$1JS dan dokumentasinya. [Harap pertimbangkan untuk menggunakan runtime APPSYNC\$1JS dan panduannya di sini.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

Anda dapat menggunakan AWS Lambda dengan AWS AppSync untuk menyelesaikan bidang GraphQL apa pun. Misalnya, kueri GraphQL mungkin mengirim panggilan ke instance Amazon Relational Database Service (Amazon RDS), dan mutasi GraphQL mungkin menulis ke aliran Amazon Kinesis. Di bagian ini, kami akan menunjukkan cara menulis fungsi Lambda yang melakukan logika bisnis berdasarkan pemanggilan operasi lapangan GraphQL.

## Buat fungsi Lambda
<a name="create-a-lam-function"></a>

Contoh berikut menunjukkan fungsi Lambda yang ditulis dalam `Node.js` yang melakukan operasi yang berbeda pada posting blog sebagai bagian dari aplikasi posting blog.

```
exports.handler = (event, context, callback) => {
    console.log("Received event {}", JSON.stringify(event, 3));
    var posts = {
         "1": {"id": "1", "title": "First book", "author": "Author1", "url": "https://amazon.com/", "content": "SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1", "ups": "100", "downs": "10"},
         "2": {"id": "2", "title": "Second book", "author": "Author2", "url": "https://amazon.com", "content": "SAMPLE TEXT AUTHOR 2 SAMPLE TEXT AUTHOR 2 SAMPLE TEXT", "ups": "100", "downs": "10"},
         "3": {"id": "3", "title": "Third book", "author": "Author3", "url": null, "content": null, "ups": null, "downs": null },
         "4": {"id": "4", "title": "Fourth book", "author": "Author4", "url": "https://www.amazon.com/", "content": "SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4", "ups": "1000", "downs": "0"},
         "5": {"id": "5", "title": "Fifth book", "author": "Author5", "url": "https://www.amazon.com/", "content": "SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT", "ups": "50", "downs": "0"} };

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

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

Fungsi Lambda ini mengambil posting dengan ID, menambahkan posting, mengambil daftar posting, dan mengambil posting terkait untuk posting tertentu.

 **Catatan:** Fungsi Lambda menggunakan `switch` pernyataan `event.field` untuk menentukan bidang mana yang sedang diselesaikan.

Buat fungsi Lambda ini menggunakan Konsol AWS Manajemen atau tumpukan. AWS CloudFormation Untuk membuat fungsi dari CloudFormation tumpukan, Anda dapat menggunakan perintah AWS Command Line Interface (AWS CLI) berikut:

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

Anda juga dapat meluncurkan CloudFormation tumpukan di AWS Wilayah AS Barat (Oregon) di AWS akun Anda dari sini:

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

## Konfigurasikan sumber data untuk Lambda
<a name="configure-data-source-for-lamlong"></a>

**Setelah Anda membuat fungsi Lambda, navigasikan ke GraphQL API Anda di AWS AppSync konsol, lalu pilih tab Sumber Data.**

Pilih **Buat sumber data**, masukkan **nama sumber data** yang ramah (misalnya,**Lambda**), dan kemudian untuk **tipe sumber data**, pilih **AWS Lambda fungsi**. Untuk **Region**, pilih Region yang sama dengan fungsi Anda. (Jika Anda membuat fungsi dari CloudFormation tumpukan yang disediakan, fungsinya mungkin ada di **US-WEST-2**.) Untuk **Fungsi ARN**, pilih Amazon Resource Name (ARN) dari fungsi Lambda Anda.

Setelah memilih fungsi Lambda, Anda dapat membuat peran baru AWS Identity and Access Management (IAM) (yang AWS AppSync menetapkan izin yang sesuai) atau memilih peran yang ada yang memiliki kebijakan sebaris berikut:

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

****  

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

------

Anda juga harus mengatur hubungan kepercayaan dengan AWS AppSync peran IAM sebagai berikut:

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

****  

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

------

## Buat skema GraphQL
<a name="creating-a-graphql-schema"></a>

Sekarang sumber data terhubung ke fungsi Lambda Anda, buat skema GraphQL.

Dari editor skema di AWS AppSync konsol, pastikan skema Anda cocok dengan skema berikut:

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

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

Setelah mendaftarkan sumber data Lambda dan skema GraphQL yang valid, Anda dapat menghubungkan bidang GraphQL ke sumber data Lambda menggunakan resolver.

Untuk membuat resolver, Anda memerlukan template pemetaan. Untuk mempelajari lebih lanjut tentang templat pemetaan, lihat[Resolver Mapping Template Overview](resolver-mapping-template-reference-overview.md#aws-appsync-resolver-mapping-template-reference-overview).

Untuk informasi selengkapnya tentang templat pemetaan Lambda, lihat. [Resolver mapping template reference for Lambda](resolver-mapping-template-reference-lambda.md#aws-appsync-resolver-mapping-template-reference-lambda)

Pada langkah ini, Anda melampirkan resolver ke fungsi Lambda untuk bidang berikut:`getPost(id:ID!): Post`,,, `allPosts: [Post]` dan. `addPost(id: ID!, author: String!, title: String, content: String, url: String): Post!` `Post.relatedPosts: [Post]`

Dari editor skema di AWS AppSync konsol, di sisi kanan, pilih **Lampirkan Resolver** untuk. `getPost(id:ID!): Post`

Kemudian, di **menu Action**, pilih **Update runtime**, lalu pilih **Unit Resolver (hanya VTL**).

Setelah itu, pilih sumber data Lambda Anda. Di bagian **template pemetaan permintaan**, pilih **Invoke And Forward Arguments**.

Ubah `payload` objek untuk menambahkan nama bidang. Template Anda akan terlihat seperti berikut:

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

Di bagian **template pemetaan respons**, pilih **Kembalikan Hasil Lambda**.

Dalam hal ini, gunakan template dasar apa adanya. Seharusnya terlihat seperti berikut:

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

Pilih **Simpan**. Anda telah berhasil melampirkan resolver pertama Anda. Ulangi operasi ini untuk bidang yang tersisa sebagai berikut:

Untuk templat pemetaan `addPost(id: ID!, author: String!, title: String, content: String, url: String): Post!` permintaan:

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

Untuk template pemetaan `addPost(id: ID!, author: String!, title: String, content: String, url: String): Post!` respons:

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

Untuk templat pemetaan `allPosts: [Post]` permintaan:

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

Untuk template pemetaan `allPosts: [Post]` respons:

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

Untuk templat pemetaan `Post.relatedPosts: [Post]` permintaan:

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

Untuk template pemetaan `Post.relatedPosts: [Post]` respons:

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

## Uji GraphQL API
<a name="testing-your-graphql-api"></a>

Sekarang fungsi Lambda Anda terhubung ke resolver GraphQL, Anda dapat menjalankan beberapa mutasi dan kueri menggunakan konsol atau aplikasi klien.

Di sisi kiri AWS AppSync konsol, pilih **Kueri**, lalu tempel kode berikut:

### AddPost Mutasi
<a name="addpost-mutation"></a>

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

### Kueri GetPost
<a name="getpost-query"></a>

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

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

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

## Mengembalikan kesalahan
<a name="returning-errors"></a>

Setiap resolusi bidang yang diberikan dapat mengakibatkan kesalahan. Dengan AWS AppSync, Anda dapat meningkatkan kesalahan dari sumber-sumber berikut:
+ Templat pemetaan permintaan atau respons
+ Fungsi Lambda

### Dari template pemetaan
<a name="from-the-mapping-template"></a>

Untuk memunculkan kesalahan yang disengaja, Anda dapat menggunakan metode `$utils.error` pembantu dari template Velocity Template Language (VTL). Dibutuhkan sebagai argumen`errorMessage`, an`errorType`, dan `data` nilai opsional. `data`Ini berguna untuk mengembalikan data tambahan kembali ke klien ketika terjadi kesalahan. `data`Objek ditambahkan ke `errors` dalam respon akhir GraphQL.

Contoh berikut menunjukkan cara menggunakannya dalam template pemetaan `Post.relatedPosts: [Post]` respons:

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

Ini menghasilkan respons GraphQL yang mirip dengan yang berikut:

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

`allPosts[0].relatedPosts`Dimana *nol* karena kesalahan dan`errorMessage`,`errorType`, dan `data` hadir dalam `data.errors[0]` objek.

### Dari fungsi Lambda
<a name="from-the-lam-function"></a>

AWS AppSync juga memahami kesalahan yang dilemparkan fungsi Lambda. Model pemrograman Lambda memungkinkan Anda meningkatkan kesalahan yang *ditangani*. Jika fungsi Lambda memunculkan kesalahan, AWS AppSync gagal menyelesaikan bidang saat ini. Hanya pesan kesalahan yang dikembalikan dari Lambda yang disetel dalam respons. Saat ini, Anda tidak dapat meneruskan data asing apa pun kembali ke klien dengan memunculkan kesalahan dari fungsi Lambda.

 **Catatan**: Jika fungsi Lambda Anda memunculkan kesalahan yang *tidak tertangani*, AWS AppSync gunakan pesan kesalahan yang ditetapkan Lambda.

Fungsi Lambda berikut menimbulkan kesalahan:

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

Ini mengembalikan respon GraphQL mirip dengan berikut ini:

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

## Kasus penggunaan lanjutan: Batching
<a name="advanced-use-case-batching"></a>

Fungsi Lambda dalam contoh ini memiliki `relatedPosts` bidang yang mengembalikan daftar posting terkait untuk posting tertentu. Dalam contoh kueri, pemanggilan `allPosts` bidang dari fungsi Lambda mengembalikan lima posting. Karena kami menetapkan bahwa kami juga ingin menyelesaikan `relatedPosts` untuk setiap posting yang dikembalikan, operasi `relatedPosts` lapangan dipanggil lima kali.

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

Meskipun ini mungkin tidak terdengar substansif dalam contoh spesifik ini, pengambilan berlebihan yang diperparah ini dapat dengan cepat merusak aplikasi.

Jika Anda mengambil `relatedPosts` lagi pada terkait yang dikembalikan `Posts` dalam kueri yang sama, jumlah pemanggilan akan meningkat secara dramatis.

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

Dalam kueri yang relatif sederhana ini, AWS AppSync akan memanggil fungsi Lambda 1 \$1 5 \$1 25 = 31 kali.

Ini adalah tantangan yang cukup umum dan sering disebut masalah N\$11 (dalam hal ini, N = 5), dan dapat menimbulkan peningkatan latensi dan biaya untuk aplikasi.

Salah satu pendekatan untuk memecahkan masalah ini adalah dengan mengumpulkan permintaan penyelesai bidang serupa bersama-sama. Dalam contoh ini, alih-alih memiliki fungsi Lambda menyelesaikan daftar posting terkait untuk satu posting tertentu, itu malah bisa menyelesaikan daftar posting terkait untuk kumpulan posting tertentu.

Untuk mendemonstrasikan hal ini, mari beralih `Post.relatedPosts: [Post]` resolver ke resolver batch-enabled.

Di sisi kanan AWS AppSync konsol, pilih `Post.relatedPosts: [Post]` resolver yang ada. Ubah template pemetaan permintaan menjadi berikut:

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

Hanya `operation` bidang yang berubah dari `Invoke` menjadi`BatchInvoke`. Bidang payload sekarang menjadi array dari apa pun yang ditentukan dalam template. Dalam contoh ini, fungsi Lambda menerima yang berikut sebagai input:

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

Kapan `BatchInvoke` ditentukan dalam template pemetaan permintaan, fungsi Lambda menerima daftar permintaan dan mengembalikan daftar hasil.

Secara khusus, daftar hasil harus sesuai dengan ukuran dan urutan entri payload permintaan sehingga AWS AppSync dapat cocok dengan hasil yang sesuai.

Dalam contoh batching ini, fungsi Lambda mengembalikan sekumpulan hasil sebagai berikut:

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

Fungsi Lambda berikut di Node.js menunjukkan fungsionalitas batching ini untuk bidang sebagai `Post.relatedPosts` berikut:

```
exports.handler = (event, context, callback) => {
    console.log("Received event {}", JSON.stringify(event, 3));
    var posts = {
         "1": {"id": "1", "title": "First book", "author": "Author1", "url": "https://amazon.com/", "content": "SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1", "ups": "100", "downs": "10"},
         "2": {"id": "2", "title": "Second book", "author": "Author2", "url": "https://amazon.com", "content": "SAMPLE TEXT AUTHOR 2 SAMPLE TEXT AUTHOR 2 SAMPLE TEXT", "ups": "100", "downs": "10"},
         "3": {"id": "3", "title": "Third book", "author": "Author3", "url": null, "content": null, "ups": null, "downs": null },
         "4": {"id": "4", "title": "Fourth book", "author": "Author4", "url": "https://www.amazon.com/", "content": "SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4", "ups": "1000", "downs": "0"},
         "5": {"id": "5", "title": "Fifth book", "author": "Author5", "url": "https://www.amazon.com/", "content": "SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT", "ups": "50", "downs": "0"} };

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

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

### Mengembalikan kesalahan individu
<a name="returning-individual-errors"></a>

Contoh sebelumnya menunjukkan bahwa dimungkinkan untuk mengembalikan satu kesalahan dari fungsi Lambda atau memunculkan kesalahan dari templat pemetaan. Untuk pemanggilan batch, memunculkan kesalahan dari fungsi Lambda menandai seluruh batch sebagai gagal. Ini mungkin dapat diterima untuk skenario tertentu di mana terjadi kesalahan yang tidak dapat dipulihkan, seperti koneksi yang gagal ke penyimpanan data. Namun, dalam kasus di mana beberapa item dalam batch berhasil dan yang lainnya gagal, dimungkinkan untuk mengembalikan kesalahan dan data yang valid. Karena AWS AppSync memerlukan respons batch untuk mencantumkan elemen yang cocok dengan ukuran asli batch, Anda harus menentukan struktur data yang dapat membedakan data yang valid dari kesalahan.

*Misalnya, jika fungsi Lambda diharapkan mengembalikan kumpulan posting terkait, Anda dapat memilih untuk mengembalikan daftar `Response` objek di mana setiap objek memiliki *data opsional, ErrorMessage, dan bidang* *ErrorType*.* Jika bidang *ErrorMessage* ada, itu berarti terjadi kesalahan.

Kode berikut menunjukkan bagaimana Anda dapat memperbarui fungsi Lambda:

```
exports.handler = (event, context, callback) => {
    console.log("Received event {}", JSON.stringify(event, 3));
    var posts = {
         "1": {"id": "1", "title": "First book", "author": "Author1", "url": "https://amazon.com/", "content": "SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1 SAMPLE TEXT AUTHOR 1", "ups": "100", "downs": "10"},
         "2": {"id": "2", "title": "Second book", "author": "Author2", "url": "https://amazon.com", "content": "SAMPLE TEXT AUTHOR 2 SAMPLE TEXT AUTHOR 2 SAMPLE TEXT", "ups": "100", "downs": "10"},
         "3": {"id": "3", "title": "Third book", "author": "Author3", "url": null, "content": null, "ups": null, "downs": null },
         "4": {"id": "4", "title": "Fourth book", "author": "Author4", "url": "https://www.amazon.com/", "content": "SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4 SAMPLE TEXT AUTHOR 4", "ups": "1000", "downs": "0"},
         "5": {"id": "5", "title": "Fifth book", "author": "Author5", "url": "https://www.amazon.com/", "content": "SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT AUTHOR 5 SAMPLE TEXT", "ups": "50", "downs": "0"} };

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

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

Untuk contoh ini, template pemetaan respons berikut mem-parsing setiap item fungsi Lambda dan memunculkan kesalahan yang terjadi:

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

Contoh ini mengembalikan respon GraphQL mirip dengan berikut:

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

### Mengkonfigurasi ukuran batching maksimum
<a name="configure-max-batch-size"></a>

Secara default, saat menggunakan`BatchInvoke`, AWS AppSync mengirim permintaan ke fungsi Lambda Anda dalam batch hingga lima item. Anda dapat mengonfigurasi ukuran batch maksimum resolver Lambda Anda.

Untuk mengonfigurasi ukuran batching maksimum pada resolver, gunakan perintah berikut di (): AWS Command Line Interface AWS CLI

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

**catatan**  
Saat menyediakan template pemetaan permintaan, Anda harus menggunakan `BatchInvoke` operasi untuk menggunakan batching.

Anda juga dapat menggunakan perintah berikut untuk mengaktifkan dan mengkonfigurasi batching pada Direct Lambda Resolvers:

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

### Konfigurasi ukuran batching maksimum dengan template VTL
<a name="configure-max-batch-size-vtl"></a>

Untuk Resolver Lambda yang memiliki templat dalam permintaan VTL, ukuran batch maksimum tidak akan berpengaruh kecuali mereka secara langsung menentukannya sebagai operasi di VTL. `BatchInvoke` Demikian pula, jika Anda melakukan mutasi tingkat atas, batching tidak dilakukan untuk mutasi karena spesifikasi GraphQL memerlukan mutasi paralel untuk dieksekusi secara berurutan.

Misalnya, ambil mutasi berikut:

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

Dengan menggunakan mutasi pertama, kita dapat membuat 10 `Items` seperti yang ditunjukkan pada cuplikan di bawah ini:

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

Dalam contoh ini, tidak `Items` akan dikelompokkan dalam grup 10 bahkan jika ukuran batch maksimum diatur ke 10 di Lambda Resolver. Sebaliknya, mereka akan mengeksekusi secara berurutan sesuai dengan spesifikasi GraphQL.

Untuk melakukan mutasi batch yang sebenarnya, Anda dapat mengikuti contoh di bawah ini menggunakan mutasi kedua:

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

Untuk informasi selengkapnya tentang penggunaan batching dengan Direct Lambda Resolvers, lihat. [Resolver Lambda Langsung](resolver-mapping-template-reference-lambda.md#direct-lambda-resolvers)

# Menggunakan OpenSearch resolver Layanan Amazon di AWS AppSync
<a name="tutorial-elasticsearch-resolvers"></a>

**catatan**  
Kami sekarang terutama mendukung runtime APPSYNC\$1JS dan dokumentasinya. [Harap pertimbangkan untuk menggunakan runtime APPSYNC\$1JS dan panduannya di sini.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

AWS AppSync mendukung penggunaan OpenSearch Layanan Amazon dari domain yang telah Anda sediakan di AWS akun Anda sendiri, asalkan tidak ada di dalam VPC. Setelah domain Anda disediakan, Anda dapat menghubungkannya menggunakan sumber data, di mana Anda dapat mengonfigurasi resolver dalam skema untuk melakukan operasi GraphQL seperti kueri, mutasi, dan langganan. Tutorial ini akan membawa Anda melalui beberapa contoh umum.

Untuk informasi selengkapnya, lihat Referensi [Template Pemetaan Resolver](resolver-mapping-template-reference-elasticsearch.md#aws-appsync-resolver-mapping-template-reference-elasticsearch) untuk. OpenSearch

## Pengaturan Satu-Klik
<a name="one-click-setup"></a>

Untuk secara otomatis mengatur titik AWS AppSync akhir GraphQL dengan OpenSearch Amazon Service yang dikonfigurasi, Anda dapat menggunakan template ini: AWS CloudFormation 

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

Setelah AWS CloudFormation penerapan selesai, Anda dapat langsung melompat ke menjalankan kueri dan mutasi [GraphQL](#tutorial-elasticsearch-resolvers-perform-queries-mutations).

## Buat Domain OpenSearch Layanan Baru
<a name="create-a-new-es-domain"></a>

Untuk memulai tutorial ini, Anda memerlukan domain OpenSearch Layanan yang ada. Jika Anda tidak memilikinya, Anda dapat menggunakan sampel berikut. Perhatikan bahwa diperlukan waktu hingga 15 menit untuk membuat domain OpenSearch Layanan sebelum Anda dapat melanjutkan untuk mengintegrasikannya dengan sumber AWS AppSync data.

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

Anda dapat meluncurkan AWS CloudFormation tumpukan berikut di wilayah US West 2 (Oregon) di AWS akun Anda:

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

## Konfigurasikan Sumber Data untuk OpenSearch Layanan
<a name="configure-data-source-for-es"></a>

**Setelah domain OpenSearch Layanan dibuat, navigasikan ke AWS AppSync GraphQL API Anda dan pilih tab Sumber Data.** Pilih **Baru** dan masukkan nama ramah untuk sumber data, seperti “oss”. Kemudian pilih ** OpenSearch domain Amazon** untuk **tipe sumber data**, pilih wilayah yang sesuai, dan Anda akan melihat domain OpenSearch Layanan Anda terdaftar. Setelah memilihnya, Anda dapat membuat peran baru dan AWS AppSync akan menetapkan izin yang sesuai peran, atau Anda dapat memilih peran yang ada, yang memiliki kebijakan sebaris berikut:

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

****  

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

------

Anda juga perlu mengatur hubungan kepercayaan AWS AppSync untuk peran itu:

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

****  

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

------

Selain itu, domain OpenSearch Layanan memiliki **Kebijakan Akses** sendiri yang dapat Anda modifikasi melalui konsol OpenSearch Layanan Amazon. Anda perlu menambahkan kebijakan yang mirip dengan yang berikut ini, dengan tindakan dan sumber daya yang sesuai untuk domain OpenSearch Layanan. Perhatikan bahwa **Principal** akan menjadi peran sumber AppSync data, yang jika Anda membiarkan konsol membuat ini, dapat ditemukan di konsol IAM.

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

****  

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

------

## Menghubungkan Resolver
<a name="connecting-a-resolver"></a>

Setelah sumber data terhubung ke domain OpenSearch Layanan Anda, Anda dapat menghubungkannya ke skema GraphQL Anda dengan resolver, seperti yang ditunjukkan pada contoh berikut:

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

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

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

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

Perhatikan bahwa ada `Post` tipe yang ditentukan pengguna dengan bidang. `id` Dalam contoh berikut, kami berasumsi ada proses (yang dapat diotomatisasi) untuk memasukkan jenis ini ke domain OpenSearch Layanan Anda, yang akan memetakan ke root jalur`/post/_doc`, di mana `post` indeks. Dari jalur root ini, Anda dapat melakukan pencarian dokumen individual, pencarian wildcard dengan`/id/post*`, atau pencarian multi-dokumen dengan jalur. `/post/_search` Misalnya, jika Anda memiliki jenis lain yang dipanggil`User`, Anda dapat mengindeks dokumen di bawah indeks baru yang disebut`user`, lalu melakukan pencarian dengan **jalur**. `/user/_search` 

Dari editor skema di AWS AppSync konsol, ubah `Posts` skema sebelumnya untuk menyertakan kueri: `searchPosts`

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

Simpan skema. Di sisi kanan, untuk`searchPosts`, pilih **Lampirkan resolver**. Di **menu Action**, pilih **Update runtime**, lalu pilih **Unit Resolver (hanya VTL**). Kemudian, pilih sumber data OpenSearch Layanan Anda. Di bawah bagian **template pemetaan permintaan**, pilih drop-down untuk **posting Query** untuk mendapatkan template dasar. `path`Memodifikasi menjadi`/post/_search`. Seharusnya terlihat seperti berikut:

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

Ini mengasumsikan bahwa skema sebelumnya memiliki dokumen yang telah diindeks di Layanan di bawah bidang. OpenSearch `post` Jika Anda menyusun data Anda secara berbeda, maka Anda harus memperbaruinya.

Di bawah bagian **template pemetaan respons**, Anda perlu menentukan `_source` filter yang sesuai jika Anda ingin mendapatkan kembali hasil data dari kueri OpenSearch Layanan dan menerjemahkan ke GraphQL. Gunakan template berikut:

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

## Memodifikasi Pencarian Anda
<a name="modifying-your-searches"></a>

Templat pemetaan permintaan sebelumnya melakukan kueri sederhana untuk semua catatan. Misalkan Anda ingin mencari oleh penulis tertentu. Selanjutnya, misalkan Anda ingin penulis itu menjadi argumen yang didefinisikan dalam kueri GraphQL Anda. Di editor skema AWS AppSync konsol, tambahkan `allPostsByAuthor` kueri:

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

Sekarang pilih **Lampirkan resolver** dan pilih sumber data OpenSearch Layanan, tetapi gunakan contoh berikut dalam template **pemetaan respons**:

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

Perhatikan bahwa `body` diisi dengan kueri istilah untuk `author` bidang, yang diteruskan dari klien sebagai argumen. [Anda dapat secara opsional memiliki informasi yang telah diisi sebelumnya, seperti teks standar, atau bahkan menggunakan utilitas lain.](resolver-context-reference.md#aws-appsync-resolver-mapping-template-context-reference)

Jika Anda menggunakan resolver ini, isi **template pemetaan respons** dengan informasi yang sama seperti contoh sebelumnya.

## Menambahkan Data ke OpenSearch Layanan
<a name="adding-data-to-es"></a>

Anda mungkin ingin menambahkan data ke domain OpenSearch Layanan Anda sebagai hasil dari mutasi GraphQL. Ini adalah mekanisme yang kuat untuk pencarian dan tujuan lainnya. Karena Anda dapat menggunakan langganan GraphQL [untuk membuat data Anda](aws-appsync-real-time-data.md) real-time, ini berfungsi sebagai mekanisme untuk memberi tahu klien tentang pembaruan data di domain Layanan Anda. OpenSearch 

Kembali ke halaman **Skema** di AWS AppSync konsol dan pilih **Lampirkan resolver untuk mutasi**. `addPost()` Pilih sumber data OpenSearch Layanan lagi dan gunakan **template pemetaan respons** berikut untuk `Posts` skema:

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

Seperti sebelumnya, ini adalah contoh bagaimana data Anda mungkin terstruktur. Jika Anda memiliki nama bidang atau indeks yang berbeda, Anda perlu memperbarui `path` dan sesuai `body` kebutuhan. Contoh ini juga menunjukkan cara menggunakan `$context.arguments` untuk mengisi template dari argumen mutasi GraphQL Anda.

Sebelum melanjutkan, gunakan template pemetaan respons berikut, yang akan mengembalikan hasil operasi mutasi atau informasi kesalahan sebagai output:

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

## Mengambil Dokumen Tunggal
<a name="retrieving-a-single-document"></a>

Terakhir, jika Anda ingin menggunakan `getPost(id:ID)` kueri dalam skema Anda untuk mengembalikan dokumen individual, temukan kueri ini di editor skema AWS AppSync konsol dan pilih **Lampirkan** resolver. Pilih sumber data OpenSearch Layanan lagi dan gunakan template pemetaan berikut:

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

Karena di `path` atas menggunakan `id` argumen dengan badan kosong, ini mengembalikan dokumen tunggal. Namun, Anda perlu menggunakan template pemetaan respons berikut, karena sekarang Anda mengembalikan satu item dan bukan daftar:

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

## Lakukan Kueri dan Mutasi
<a name="tutorial-elasticsearch-resolvers-perform-queries-mutations"></a>

Anda sekarang harus dapat melakukan operasi GraphQL terhadap OpenSearch domain Layanan Anda. Arahkan ke tab **Kueri** AWS AppSync konsol dan tambahkan catatan baru:

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

Anda akan melihat hasil mutasi di sebelah kanan. Demikian pula, Anda sekarang dapat menjalankan `searchPosts` kueri terhadap domain OpenSearch Layanan Anda:

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

## Praktik Terbaik
<a name="best-practices"></a>
+ OpenSearch Layanan harus untuk query data, bukan sebagai database utama Anda. [Anda mungkin ingin menggunakan OpenSearch Layanan bersama dengan Amazon DynamoDB sebagaimana diuraikan dalam Menggabungkan GraphQL Resolvers.](tutorial-combining-graphql-resolvers.md#aws-appsync-tutorial-combining-graphql-resolvers)
+ Hanya berikan akses ke domain Anda dengan mengizinkan peran AWS AppSync layanan mengakses klaster.
+ Anda dapat memulai dari yang kecil dalam pengembangan, dengan cluster berbiaya terendah, dan kemudian pindah ke cluster yang lebih besar dengan ketersediaan tinggi (HA) saat Anda pindah ke produksi.

# Menggunakan resolver lokal di AWS AppSync
<a name="tutorial-local-resolvers"></a>

**catatan**  
Kami sekarang terutama mendukung runtime APPSYNC\$1JS dan dokumentasinya. [Harap pertimbangkan untuk menggunakan runtime APPSYNC\$1JS dan panduannya di sini.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

AWS AppSync memungkinkan Anda menggunakan sumber data yang didukung (AWS Lambda, Amazon DynamoDB, atau OpenSearch Amazon Service) untuk melakukan berbagai operasi. Namun, dalam skenario tertentu, panggilan ke sumber data yang didukung mungkin tidak diperlukan.

Di sinilah resolver lokal berguna. Alih-alih memanggil sumber data jarak jauh, resolver lokal hanya akan **meneruskan** hasil template pemetaan permintaan ke template pemetaan respons. Resolusi lapangan tidak akan pergi AWS AppSync.

Resolver lokal berguna untuk beberapa kasus penggunaan. Kasus penggunaan yang paling populer adalah mempublikasikan notifikasi tanpa memicu panggilan sumber data. Untuk mendemonstrasikan kasus penggunaan ini, mari buat aplikasi paging; di mana pengguna dapat saling berhalaman. Contoh ini memanfaatkan *Langganan*, jadi jika Anda tidak terbiasa dengan *Langganan*, Anda dapat mengikuti tutorial Data [Waktu Nyata](aws-appsync-real-time-data.md).

## Buat Aplikasi Paging
<a name="create-the-paging-application"></a>

Dalam aplikasi paging kami, klien dapat berlangganan kotak masuk, dan mengirim halaman ke klien lain. Setiap halaman berisi pesan. Berikut adalah skema:

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

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

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

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

type Query {
    me: String
}
```

Mari kita lampirkan resolver di lapangan. `Mutation.page` Di panel **Schema**, klik *Lampirkan Resolver* di sebelah definisi bidang di panel kanan. Buat sumber data baru tipe *None* dan beri nama *PageDataSource*.

Untuk template pemetaan permintaan, masukkan:

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

Dan untuk template pemetaan respons, pilih default *Teruskan hasilnya*. Simpan resolver Anda. Aplikasi Anda sekarang siap, mari kita halaman\$1

## Kirim dan berlangganan halaman
<a name="send-and-subscribe-to-pages"></a>

Agar klien dapat menerima halaman, mereka harus terlebih dahulu berlangganan kotak masuk.

Di panel **Queries** mari kita jalankan langganan: `inbox`

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

 *Nadia* akan menerima halaman setiap kali `Mutation.page` mutasi dipanggil. Mari kita panggil mutasi dengan mengeksekusi mutasi:

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

Kami baru saja mendemonstrasikan penggunaan resolver lokal, dengan mengirim Halaman dan menerimanya tanpa pergi. AWS AppSync

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

**catatan**  
Kami sekarang terutama mendukung runtime APPSYNC\$1JS dan dokumentasinya. [Harap pertimbangkan untuk menggunakan runtime APPSYNC\$1JS dan panduannya di sini.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

Resolver dan bidang dalam skema GraphQL memiliki hubungan 1:1 dengan tingkat fleksibilitas yang besar. Karena sumber data dikonfigurasi pada resolver secara independen dari skema, Anda memiliki kemampuan untuk jenis GraphQL untuk diselesaikan atau dimanipulasi melalui sumber data yang berbeda, pencampuran dan pencocokan pada skema untuk memenuhi kebutuhan Anda.

Contoh skenario berikut menunjukkan cara mencampur dan mencocokkan sumber data dalam skema Anda. Sebelum Anda mulai, kami sarankan Anda terbiasa dengan pengaturan sumber data dan resolver untuk AWS Lambda, Amazon DynamoDB, dan OpenSearch Amazon Service seperti yang dijelaskan dalam tutorial sebelumnya.

## Contoh skema
<a name="example-schema"></a>

Skema berikut memiliki jenis `Post` dengan 3 `Query` operasi dan 3 `Mutation` operasi didefinisikan:

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

Dalam contoh ini Anda akan memiliki total 6 resolver untuk dilampirkan. Salah satu cara yang mungkin adalah agar semua ini berasal dari tabel Amazon DynamoDB, yang `Posts` disebut, `AllPosts` di mana menjalankan pemindaian `searchPosts` dan menjalankan kueri, seperti yang diuraikan dalam Referensi Template Pemetaan [DynamoDB](resolver-mapping-template-reference-dynamodb.md#aws-appsync-resolver-mapping-template-reference-dynamodb) Resolver. Namun, ada alternatif untuk memenuhi kebutuhan bisnis Anda, seperti menyelesaikan kueri GraphQL ini dari Lambda atau Layanan. OpenSearch 

## Mengubah data melalui resolver
<a name="alter-data-through-resolvers"></a>

Anda mungkin perlu mengembalikan hasil dari database seperti DynamoDB (atau Amazon Aurora) ke klien dengan beberapa atribut diubah. Ini mungkin karena pemformatan tipe data, seperti perbedaan stempel waktu pada klien, atau untuk menangani masalah kompatibilitas mundur. Untuk tujuan ilustrasi, dalam contoh berikut, AWS Lambda fungsi memanipulasi up-votes dan down-votes untuk posting blog dengan menetapkan nomor acak setiap kali GraphQL resolver dipanggil:

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

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

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

Ini adalah fungsi Lambda yang benar-benar valid dan dapat dilampirkan ke `AllPosts` bidang dalam skema GraphQL sehingga setiap kueri yang mengembalikan semua hasil mendapat angka acak untuk naik/turun.

## DynamoDB dan Layanan OpenSearch
<a name="ddb-and-es"></a>

Untuk beberapa aplikasi, Anda mungkin melakukan mutasi atau kueri pencarian sederhana terhadap DynamoDB, dan memiliki proses latar belakang mentransfer dokumen ke Layanan. OpenSearch Anda kemudian dapat melampirkan `searchPosts` Resolver ke sumber data OpenSearch Layanan dan mengembalikan hasil pencarian (dari data yang berasal dari DynamoDB) menggunakan query GraphQL. Ini bisa sangat kuat saat menambahkan operasi pencarian lanjutan ke aplikasi Anda seperti kata kunci, kecocokan kata kabur atau bahkan pencarian geospasial. Mentransfer data dari DynamoDB dapat dilakukan melalui proses ETL atau sebagai alternatif Anda dapat melakukan streaming dari DynamoDB menggunakan Lambda. Anda dapat meluncurkan contoh lengkap ini menggunakan AWS CloudFormation tumpukan berikut di Wilayah AS Barat 2 (Oregon) di AWS akun Anda:

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

Skema dalam contoh ini memungkinkan Anda menambahkan posting menggunakan DynamoDB resolver sebagai berikut:

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

Ini menulis data ke DynamoDB yang kemudian mengalirkan data melalui Lambda ke OpenSearch Amazon Service yang dapat Anda cari untuk semua posting dengan bidang yang berbeda. Misalnya, karena data ada di OpenSearch Layanan Amazon, Anda dapat mencari bidang penulis atau konten dengan teks bentuk bebas, bahkan dengan spasi, sebagai berikut:

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

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

Karena data ditulis langsung ke DynamoDB, Anda masih dapat melakukan operasi pencarian daftar atau item yang efisien terhadap tabel dengan dan kueri. `allPosts{...}` `singlePost{...}` Tumpukan ini menggunakan kode contoh berikut untuk aliran DynamoDB:

 **Catatan:** Kode ini misalnya saja.

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

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

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

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

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

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

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

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

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

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

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

Anda kemudian dapat menggunakan aliran DynamoDB untuk melampirkan ini ke tabel DynamoDB dengan kunci `id` utama, dan setiap perubahan pada sumber DynamoDB akan mengalir ke domain Layanan Anda. OpenSearch Untuk informasi selengkapnya tentang mengonfigurasi ini, lihat dokumentasi [DynamoDB Streams](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Streams.Lambda.html).

# Menggunakan operasi batch DynamoDB di AWS AppSync
<a name="tutorial-dynamodb-batch"></a>

**catatan**  
Kami sekarang terutama mendukung runtime APPSYNC\$1JS dan dokumentasinya. [Harap pertimbangkan untuk menggunakan runtime APPSYNC\$1JS dan panduannya di sini.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

AWS AppSync mendukung penggunaan operasi batch Amazon DynamoDB di satu atau beberapa tabel dalam satu wilayah. Operasi yang didukung adalah`BatchGetItem`,`BatchPutItem`, dan`BatchDeleteItem`. Dengan menggunakan fitur-fitur ini di AWS AppSync, Anda dapat melakukan tugas-tugas seperti:
+ Lewati daftar kunci dalam satu kueri dan kembalikan hasil dari tabel
+ Membaca catatan dari satu atau beberapa tabel dalam satu kueri
+ Tulis catatan secara massal ke satu atau lebih tabel
+ Menulis atau menghapus catatan secara kondisional dalam beberapa tabel yang mungkin memiliki hubungan

Menggunakan operasi batch dengan DynamoDB AWS AppSync in adalah teknik canggih yang membutuhkan sedikit pemikiran dan pengetahuan ekstra tentang operasi backend dan struktur tabel Anda. Selain itu, operasi batch AWS AppSync memiliki dua perbedaan utama dari operasi non-batch:
+ Peran sumber data harus memiliki izin ke semua tabel yang akan diakses oleh resolver.
+ Spesifikasi tabel untuk resolver adalah bagian dari template pemetaan.

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

Seperti resolver lainnya, Anda perlu membuat sumber data AWS AppSync dan membuat peran atau menggunakan yang sudah ada. Karena operasi batch memerlukan izin yang berbeda pada tabel DynamoDB, Anda perlu memberikan izin peran yang dikonfigurasi untuk tindakan baca atau tulis:

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

****  

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

------

 **Catatan**: Peran terkait dengan sumber data di AWS AppSync, dan resolver pada bidang dipanggil terhadap sumber data. Sumber data yang dikonfigurasi untuk mengambil terhadap DynamoDB hanya memiliki satu tabel yang ditentukan, untuk menjaga konfigurasi tetap sederhana. Oleh karena itu, saat melakukan operasi batch terhadap beberapa tabel dalam satu resolver, yang merupakan tugas yang lebih maju, Anda harus memberikan peran pada akses sumber data tersebut ke tabel mana pun yang akan berinteraksi dengan resolver. Ini akan dilakukan di bidang **Sumber Daya** dalam kebijakan IAM di atas. Konfigurasi tabel untuk membuat panggilan batch terhadap dilakukan dalam template resolver, yang kami jelaskan di bawah ini.

## Sumber Data
<a name="data-source"></a>

Demi kesederhanaan, kita akan menggunakan sumber data yang sama untuk semua resolver yang digunakan dalam tutorial ini. Pada tab **Sumber data**, buat sumber data DynamoDB baru dan beri nama. **BatchTutorial** Nama tabel dapat berupa apa saja karena nama tabel ditentukan sebagai bagian dari template pemetaan permintaan untuk operasi batch. Kami akan memberikan nama tabel`empty`.

Untuk tutorial ini, peran apa pun dengan kebijakan inline berikut akan berfungsi:

## Batch Tabel Tunggal
<a name="single-table-batch"></a>

**Awas**  
`BatchPutItem`dan `BatchDeleteItem` tidak didukung saat digunakan dengan deteksi dan resolusi konflik. Pengaturan ini harus dinonaktifkan untuk mencegah kemungkinan kesalahan.

Untuk contoh ini, misalkan Anda memiliki satu tabel bernama **Posts** yang ingin Anda tambahkan dan hapus item dengan operasi batch. Gunakan skema berikut, perhatikan bahwa untuk kueri, kita akan meneruskan daftar IDs:

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

input PostInput {
    id: ID!
    title: String
}

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

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

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

Lampirkan resolver ke `batchAdd()` bidang dengan Template **Pemetaan Permintaan** berikut. Ini secara otomatis mengambil setiap item dalam tipe `input PostInput` GraphQL dan membangun peta, yang diperlukan untuk operasi: `BatchPutItem`

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

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

Dalam hal ini, **Response Mapping Template** adalah passthrough sederhana, tetapi nama tabel ditambahkan `..data.Posts` ke objek konteks sebagai berikut:

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

Sekarang navigasikan ke halaman **Kueri** AWS AppSync konsol dan jalankan mutasi **batchAdd** berikut:

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

**Anda akan melihat hasil yang dicetak ke layar, dan dapat secara independen memvalidasi melalui konsol DynamoDB yang ditulis oleh kedua nilai ke tabel Posts.**

Selanjutnya, lampirkan resolver ke `batchGet()` bidang dengan Template **Pemetaan Permintaan** berikut. Ini secara otomatis mengambil setiap item dalam tipe `ids:[]` GraphQL dan membangun peta yang diperlukan untuk operasi: `BatchGetItem`

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

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

**Template Pemetaan Respons** sekali lagi merupakan passthrough sederhana, dengan sekali lagi nama tabel ditambahkan `..data.Posts` ke objek konteks:

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

Sekarang kembali ke halaman **Queries** AWS AppSync konsol, dan jalankan **BatchGet** Query berikut:

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

Ini akan mengembalikan hasil untuk dua `id` nilai yang Anda tambahkan sebelumnya. Perhatikan bahwa `null` nilai yang dikembalikan untuk `id` dengan nilai`3`. Ini karena belum ada catatan di tabel **Posts** Anda dengan nilai itu. Perhatikan juga bahwa AWS AppSync mengembalikan hasil dalam urutan yang sama dengan kunci yang diteruskan ke kueri, yang merupakan fitur tambahan yang AWS AppSync dilakukan atas nama Anda. Jadi jika Anda beralih ke`batchGet(ids:[1,3,2)`, Anda akan melihat urutannya berubah. Anda juga akan tahu mana yang `id` mengembalikan `null` nilai.

Terakhir, lampirkan resolver ke `batchDelete()` bidang dengan Template **Pemetaan Permintaan** berikut. Ini secara otomatis mengambil setiap item dalam tipe `ids:[]` GraphQL dan membangun peta yang diperlukan untuk operasi: `BatchGetItem`

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

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

**Template Pemetaan Respons** sekali lagi merupakan passthrough sederhana, dengan sekali lagi nama tabel ditambahkan `..data.Posts` ke objek konteks:

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

Sekarang kembali ke halaman **Queries** AWS AppSync konsol, dan jalankan mutasi **BatchDelete** berikut:

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

Catatan dengan `id` `1` dan sekarang `2` harus dihapus. Jika Anda menjalankan kembali `batchGet()` kueri dari sebelumnya, ini akan kembali`null`.

## Batch Multi-Tabel
<a name="multi-table-batch"></a>

**Awas**  
`BatchPutItem`dan `BatchDeleteItem` tidak didukung saat digunakan dengan deteksi dan resolusi konflik. Pengaturan ini harus dinonaktifkan untuk mencegah kemungkinan kesalahan.

AWS AppSync juga memungkinkan Anda untuk melakukan operasi batch di seluruh tabel. Mari kita membangun aplikasi yang lebih kompleks. Bayangkan kita sedang membangun aplikasi Kesehatan Hewan Peliharaan, di mana sensor melaporkan lokasi hewan peliharaan dan suhu tubuh. Sensor bertenaga baterai dan mencoba untuk terhubung ke jaringan setiap beberapa menit. Ketika sensor membuat koneksi, ia mengirimkan bacaannya ke AWS AppSync API kami. Pemicu kemudian menganalisis data sehingga dasbor dapat disajikan kepada pemilik hewan peliharaan. Mari kita fokus pada merepresentasikan interaksi antara sensor dan penyimpanan data backend.

**Sebagai prasyarat, pertama-tama mari kita buat dua tabel DynamoDB; LocationReadings akan menyimpan pembacaan lokasi sensor dan TemperatureReadings **akan** menyimpan pembacaan suhu sensor.** Kedua tabel kebetulan berbagi struktur kunci utama yang sama: `sensorId (String)` menjadi kunci partisi, dan `timestamp (String)` kunci sortir.

Mari kita gunakan skema GraphQL berikut:

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

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

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

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

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

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

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

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

### BatchPutItem - Bacaan Sensor Perekaman
<a name="batchputitem-recording-sensor-readings"></a>

Sensor kami harus dapat mengirim bacaan mereka setelah mereka terhubung ke internet. `Mutation.recordReadings`Bidang GraphQL adalah API yang akan mereka gunakan untuk melakukannya. Mari lampirkan resolver untuk menghidupkan API kita.

Pilih **Lampirkan** di sebelah `Mutation.recordReadings` bidang. Pada layar berikutnya, pilih sumber `BatchTutorial` data yang sama yang dibuat di awal tutorial.

Mari tambahkan template pemetaan permintaan berikut:

 **Templat Pemetaan Permintaan** 

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

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

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

Seperti yang Anda lihat, `BatchPutItem` operasi memungkinkan kita untuk menentukan beberapa tabel.

Mari kita gunakan template pemetaan respons berikut.

 **Templat Pemetaan Respon** 

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

Dengan operasi batch, mungkin ada kesalahan dan hasil yang dikembalikan dari pemanggilan. Dalam hal ini, kami bebas melakukan beberapa penanganan kesalahan tambahan.

 **Catatan**: Penggunaan `$utils.appendError()` mirip dengan`$util.error()`, dengan perbedaan utama bahwa itu tidak mengganggu evaluasi template pemetaan. Sebaliknya, itu menandakan ada kesalahan dengan bidang, tetapi memungkinkan template untuk dievaluasi dan akibatnya mengembalikan data kembali ke pemanggil. Kami menyarankan Anda menggunakan `$utils.appendError()` ketika aplikasi Anda perlu mengembalikan sebagian hasil.

Simpan resolver dan navigasikan ke halaman **Kueri** konsol. AWS AppSync Mari kita kirim beberapa pembacaan sensor\$1

Jalankan mutasi berikut:

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

Kami mengirim 10 pembacaan sensor dalam satu mutasi, dengan pembacaan dibagi menjadi dua tabel. ****Gunakan konsol DynamoDB untuk memvalidasi bahwa data muncul di tabel LocationReadings dan TemperatureReadings.****

### BatchDeleteItem - Menghapus Bacaan Sensor
<a name="batchdeleteitem-deleting-sensor-readings"></a>

Demikian pula, kita juga perlu menghapus batch pembacaan sensor. Mari kita gunakan bidang `Mutation.deleteReadings` GraphQL untuk tujuan ini. Pilih **Lampirkan** di sebelah `Mutation.recordReadings` bidang. Pada layar berikutnya, pilih sumber `BatchTutorial` data yang sama yang dibuat di awal tutorial.

Mari kita gunakan template pemetaan permintaan berikut.

 **Templat Pemetaan Permintaan** 

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

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

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

Template pemetaan respons sama dengan yang kami gunakan. `Mutation.recordReadings`

 **Templat Pemetaan Respon** 

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

Simpan resolver dan navigasikan ke halaman **Kueri** konsol. AWS AppSync Sekarang, mari kita hapus beberapa pembacaan sensor\$1

Jalankan mutasi berikut:

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

****Validasi melalui konsol DynamoDB bahwa dua pembacaan ini telah dihapus dari tabel LocationReadings dan TemperatureReadings.****

### BatchGetItem - Ambil Bacaan
<a name="batchgetitem-retrieve-readings"></a>

Operasi umum lainnya untuk aplikasi Kesehatan Hewan Peliharaan kami adalah mengambil pembacaan untuk sensor pada titik waktu tertentu. Mari kita lampirkan resolver ke bidang GraphQL pada `Query.getReadings` skema kita. Pilih **Lampirkan**, dan pada layar berikutnya pilih sumber `BatchTutorial` data yang sama yang dibuat di awal tutorial.

Mari tambahkan template pemetaan permintaan berikut.

 **Templat Pemetaan Permintaan** 

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

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

Perhatikan bahwa kita sekarang menggunakan **BatchGetItem**operasi.

Template pemetaan respons kami akan sedikit berbeda karena kami memilih untuk mengembalikan `SensorReading` daftar. Mari kita memetakan hasil pemanggilan ke bentuk yang diinginkan.

 **Templat Pemetaan Respon** 

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

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

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

$util.toJson($sensorReadings)
```

Simpan resolver dan navigasikan ke halaman **Kueri** konsol. AWS AppSync Sekarang, mari kita ambil pembacaan sensor\$1

Jalankan kueri berikut:

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

Kami telah berhasil mendemonstrasikan penggunaan operasi batch DynamoDB menggunakan. AWS AppSync

## Penanganan Kesalahan
<a name="error-handling"></a>

Dalam AWS AppSync, operasi sumber data terkadang dapat mengembalikan sebagian hasil. Hasil sebagian adalah istilah yang akan kita gunakan untuk menunjukkan ketika output dari suatu operasi terdiri dari beberapa data dan kesalahan. Karena penanganan kesalahan secara inheren spesifik aplikasi, AWS AppSync memberi Anda kesempatan untuk menangani kesalahan dalam template pemetaan respons. Kesalahan pemanggilan resolver, jika ada, tersedia dari konteks sebagai. `$ctx.error` Kesalahan pemanggilan selalu menyertakan pesan dan tipe, dapat diakses sebagai properti `$ctx.error.message` dan. `$ctx.error.type` Selama pemanggilan template pemetaan respons, Anda dapat menangani sebagian hasil dengan tiga cara:

1. menelan kesalahan pemanggilan hanya dengan mengembalikan data

1. meningkatkan kesalahan (menggunakan`$util.error(...)`) dengan menghentikan evaluasi template pemetaan respons, yang tidak akan mengembalikan data apa pun.

1. tambahkan kesalahan (menggunakan`$util.appendError(...)`) dan juga mengembalikan data

Mari kita tunjukkan masing-masing dari tiga poin di atas dengan operasi batch DynamoDB\$1

### Operasi Batch DynamoDB
<a name="dynamodb-batch-operations"></a>

Dengan operasi batch DynamoDB, ada kemungkinan bahwa batch sebagian selesai. Artinya, ada kemungkinan bahwa beberapa item atau kunci yang diminta dibiarkan tidak diproses. Jika AWS AppSync tidak dapat menyelesaikan batch, item yang belum diproses dan kesalahan pemanggilan akan disetel pada konteksnya.

Kami akan menerapkan penanganan kesalahan menggunakan konfigurasi `Query.getReadings` bidang dari `BatchGetItem` operasi dari bagian sebelumnya dari tutorial ini. Kali ini, mari kita berpura-pura bahwa saat mengeksekusi `Query.getReadings` field, tabel DynamoDB `temperatureReadings` kehabisan throughput yang disediakan. DynamoDB mengangkat **ProvisionedThroughputExceededException**a pada upaya kedua AWS AppSync dengan memproses elemen yang tersisa dalam batch.

JSON berikut mewakili konteks serial setelah pemanggilan batch DynamoDB tetapi sebelum template pemetaan respons dievaluasi.

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

Beberapa hal yang perlu diperhatikan pada konteksnya:
+ **kesalahan pemanggilan telah disetel pada konteks di `$ctx.error` by AWS AppSync, dan jenis kesalahan telah disetel ke DynamoDB:. ProvisionedThroughputExceededException**
+ hasil dipetakan per tabel di bawah`$ctx.result.data`, meskipun ada kesalahan
+ kunci yang dibiarkan tidak diproses tersedia di`$ctx.result.data.unprocessedKeys`. Di sini, AWS AppSync tidak dapat mengambil item dengan kunci (sensorid:1, stempel waktu: 2018-02-01T 17:21:05.000 \$1 08:00) karena throughput tabel yang tidak mencukupi.

 **Catatan**: Untuk`BatchPutItem`, itu`$ctx.result.data.unprocessedItems`. Untuk`BatchDeleteItem`, itu`$ctx.result.data.unprocessedKeys`.

Mari kita tangani kesalahan ini dengan tiga cara berbeda.

#### 1. Menelan kesalahan pemanggilan
<a name="swallowing-the-invocation-error"></a>

Mengembalikan data tanpa menangani kesalahan pemanggilan secara efektif menelan kesalahan, membuat hasil untuk bidang GraphQL yang diberikan selalu berhasil.

Template pemetaan respons yang kita tulis sudah tidak asing lagi dan hanya berfokus pada data hasil.

Templat pemetaan respons:

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

Tanggapan GraphQL:

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

Tidak ada kesalahan yang akan ditambahkan ke respons kesalahan karena hanya data yang ditindaklanjuti.

#### 2. Memunculkan kesalahan untuk membatalkan eksekusi template
<a name="raising-an-error-to-abort-the-template-execution"></a>

Ketika kegagalan sebagian harus diperlakukan sebagai kegagalan total dari perspektif klien, Anda dapat membatalkan eksekusi template untuk mencegah pengembalian data. Metode `$util.error(...)` utilitas mencapai perilaku ini dengan tepat.

Templat pemetaan respons:

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

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

Tanggapan GraphQL:

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

*Meskipun beberapa hasil mungkin telah dikembalikan dari operasi batch DynamoDB, kami memilih untuk memunculkan kesalahan sehingga bidang `getReadings` GraphQL adalah nol dan kesalahan telah ditambahkan ke blok kesalahan respons GraphQL.*

#### 3. Menambahkan kesalahan untuk mengembalikan data dan kesalahan
<a name="appending-an-error-to-return-both-data-and-errors"></a>

Dalam kasus tertentu, untuk memberikan pengalaman pengguna yang lebih baik, aplikasi dapat mengembalikan sebagian hasil dan memberi tahu klien mereka tentang item yang belum diproses. Klien dapat memutuskan untuk menerapkan coba lagi atau menerjemahkan kesalahan kembali ke pengguna akhir. Ini `$util.appendError(...)` adalah metode utilitas yang memungkinkan perilaku ini dengan membiarkan desainer aplikasi menambahkan kesalahan pada konteks tanpa mengganggu evaluasi template. Setelah mengevaluasi template, AWS AppSync akan memproses kesalahan konteks apa pun dengan menambahkannya ke blok kesalahan respons GraphQL.

Templat pemetaan respons:

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

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

Kami meneruskan kesalahan pemanggilan dan elemen UnprocessedKeys di dalam blok kesalahan respons GraphQL. `getReadings`Bidang ini juga mengembalikan sebagian data dari tabel **LocationReadings** seperti yang Anda lihat pada respons di bawah ini.

Tanggapan GraphQL:

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

# Melakukan transaksi DynamoDB di AWS AppSync
<a name="tutorial-dynamodb-transact"></a>

**catatan**  
Kami sekarang terutama mendukung runtime APPSYNC\$1JS dan dokumentasinya. [Harap pertimbangkan untuk menggunakan runtime APPSYNC\$1JS dan panduannya di sini.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

AWS AppSync mendukung penggunaan operasi transaksi Amazon DynamoDB di satu atau beberapa tabel dalam satu wilayah. Operasi yang didukung adalah `TransactGetItems` dan`TransactWriteItems`. Dengan menggunakan fitur-fitur ini di AWS AppSync, Anda dapat melakukan tugas-tugas seperti:
+ Lewati daftar kunci dalam satu kueri dan kembalikan hasil dari tabel
+ Membaca catatan dari satu atau beberapa tabel dalam satu kueri
+ Menulis catatan dalam transaksi ke satu atau beberapa tabel dengan all-or-nothing cara
+ Jalankan transaksi ketika beberapa kondisi terpenuhi

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

Seperti resolver lainnya, Anda perlu membuat sumber data AWS AppSync dan membuat peran atau menggunakan yang sudah ada. Karena operasi transaksi memerlukan izin yang berbeda pada tabel DynamoDB, Anda perlu memberikan izin peran yang dikonfigurasi untuk tindakan baca atau tulis:

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

------

 **Catatan**: Peran terkait dengan sumber data di AWS AppSync, dan resolver pada bidang dipanggil terhadap sumber data. Sumber data yang dikonfigurasi untuk mengambil terhadap DynamoDB hanya memiliki satu tabel yang ditentukan, untuk menjaga konfigurasi tetap sederhana. Oleh karena itu, saat melakukan operasi transaksi terhadap beberapa tabel dalam satu resolver, yang merupakan tugas yang lebih maju, Anda harus memberikan peran pada akses sumber data tersebut ke tabel mana pun yang akan berinteraksi dengan resolver. Ini akan dilakukan di bidang **Sumber Daya** dalam kebijakan IAM di atas. Konfigurasi panggilan transaksi terhadap tabel dilakukan dalam template resolver, yang kami jelaskan di bawah ini.

## Sumber Data
<a name="data-source"></a>

Demi kesederhanaan, kita akan menggunakan sumber data yang sama untuk semua resolver yang digunakan dalam tutorial ini. Pada tab **Sumber data**, buat sumber data DynamoDB baru dan beri nama. **TransactTutorial** Nama tabel dapat berupa apa saja karena nama tabel ditentukan sebagai bagian dari template pemetaan permintaan untuk operasi transaksi. Kami akan memberikan nama tabel`empty`.

Kita akan memiliki dua tabel yang disebut **SavingAccounts** **dan** CheckingAccounts, `accountNumber` keduanya dengan kunci partisi, dan tabel TransactionHistory **dengan** as partition key. `transactionId`

Untuk tutorial ini, peran apa pun dengan kebijakan inline berikut akan berfungsi. Ganti `region` dan `accountId` dengan wilayah dan ID akun Anda:

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

------

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

Untuk contoh ini, konteksnya adalah transaksi perbankan klasik, di mana kita akan menggunakan `TransactWriteItems` untuk:
+ Transfer uang dari rekening tabungan ke rekening giro
+ Menghasilkan catatan transaksi baru untuk setiap transaksi

Dan kemudian kita akan menggunakan `TransactGetItems` untuk mengambil rincian dari rekening tabungan dan rekening giro.

**Awas**  
`TransactWriteItems`tidak didukung saat digunakan dengan deteksi dan resolusi konflik. Pengaturan ini harus dinonaktifkan untuk mencegah kemungkinan kesalahan.

Kami mendefinisikan skema GraphQL kami sebagai berikut:

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

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

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

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

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

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

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

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

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

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

### TransactWriteItems - Mengisi Akun
<a name="transactwriteitems-populate-accounts"></a>

Untuk mentransfer uang antar akun, kita perlu mengisi tabel dengan detailnya. Kami akan menggunakan `Mutation.populateAccounts` operasi GraphQL untuk melakukannya.

Di bagian Skema, klik **Lampirkan** di sebelah `Mutation.populateAccounts` operasi. Buka Resolver Unit VTL, lalu pilih sumber data yang sama. `TransactTutorial`

Sekarang gunakan template pemetaan permintaan berikut:

 **Templat Pemetaan Permintaan** 

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

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

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

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

Dan template pemetaan respons berikut:

 **Templat Pemetaan Respon** 

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

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

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

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

$util.toJson($transactionResult)
```

Simpan resolver dan navigasikan ke bagian **Kueri** di AWS AppSync konsol untuk mengisi akun.

Jalankan mutasi berikut:

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

Kami mengisi 3 rekening tabungan dan 3 rekening giro dalam satu mutasi.

****Gunakan konsol DynamoDB untuk memvalidasi bahwa data muncul di tabel SavingAccounts dan CheckingAccounts.****

### TransactWriteItems - Transfer Uang
<a name="transactwriteitems-transfer-money"></a>

Lampirkan resolver ke `transferMoney` mutasi dengan Template Pemetaan **Permintaan** berikut. Perhatikan nilai-nilai`amounts`,`savingAccountNumbers`, `checkingAccountNumbers` dan sama.

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

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

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

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

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

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

Kami akan memiliki 3 transaksi perbankan dalam satu `TransactWriteItems` operasi. Gunakan **Template Pemetaan Respons** berikut:

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

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

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

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

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

$util.toJson($transactionResult)
```

Sekarang arahkan ke bagian **Kueri** AWS AppSync konsol dan jalankan mutasi **TransferMoney** sebagai berikut:

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

Kami mengirim 2 transaksi perbankan dalam satu mutasi. ****Gunakan konsol DynamoDB untuk memvalidasi data yang muncul di tabel SavingAccounts, **CheckingAccounts**, dan TransactionHistory.****

### TransactGetItems - Ambil Akun
<a name="transactgetitems-retrieve-accounts"></a>

Untuk mengambil detail dari rekening tabungan dan rekening giro dalam satu permintaan transaksional, kami akan melampirkan resolver ke operasi `Query.getAccounts` GraphQL pada skema kami. Pilih **Lampirkan**, pergi ke VTL Unit Resolvers, lalu pada layar berikutnya, pilih sumber `TransactTutorial` data yang sama yang dibuat di awal tutorial. Konfigurasikan template sebagai berikut:

 **Templat Pemetaan Permintaan** 

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

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

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

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

 **Templat Pemetaan Respon** 

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

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

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

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

$util.toJson($transactionResult)
```

Simpan resolver dan navigasikan ke bagian **Kueri** konsol. AWS AppSync Untuk mengambil akun tabungan dan memeriksa akun, jalankan kueri berikut:

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

Kami telah berhasil menunjukkan penggunaan transaksi DynamoDB menggunakan. AWS AppSync

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

**catatan**  
Kami sekarang terutama mendukung runtime APPSYNC\$1JS dan dokumentasinya. [Harap pertimbangkan untuk menggunakan runtime APPSYNC\$1JS dan panduannya di sini.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

AWS AppSync memungkinkan Anda menggunakan sumber data yang didukung (yaitu, Amazon DynamoDB AWS Lambda, Amazon Service, atau OpenSearch Amazon Aurora) untuk melakukan berbagai operasi, selain titik akhir HTTP arbitrer untuk menyelesaikan bidang GraphQL. Setelah titik akhir HTTP Anda tersedia, Anda dapat menghubungkannya menggunakan sumber data. Kemudian, Anda dapat mengonfigurasi resolver dalam skema untuk melakukan operasi GraphQL seperti kueri, mutasi, dan langganan. Tutorial ini memandu Anda melalui beberapa contoh umum.

Dalam tutorial ini Anda menggunakan REST API (dibuat menggunakan Amazon API Gateway dan Lambda) dengan titik akhir AWS AppSync GraphQL.

## Pengaturan Satu-Klik
<a name="one-click-setup"></a>

Jika ingin mengatur titik akhir GraphQL secara otomatis dengan titik akhir HTTP yang AWS AppSync dikonfigurasi (menggunakan Amazon API Gateway dan Lambda), Anda dapat menggunakan templat berikut: AWS CloudFormation 

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

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

Anda dapat menggunakan AWS CloudFormation template berikut untuk menyiapkan titik akhir REST yang berfungsi untuk tutorial ini:

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

 AWS CloudFormation Tumpukan melakukan langkah-langkah berikut:

1. Menyiapkan fungsi Lambda yang berisi logika bisnis Anda untuk layanan mikro Anda.

1. Menyiapkan API REST API Gateway dengan kombinasi endpoint/method/content tipe berikut:


****  

| Jalur Sumber Daya API | Metode HTTP | Jenis Konten yang Didukung | 
| --- | --- | --- | 
|  /v1/pengguna  |  POST  |  aplikasi/json  | 
|  /v1/pengguna  |  GET  |  aplikasi/json  | 
|  /v1/pengguna/1  |  GET  |  aplikasi/json  | 
|  /v1/pengguna/1  |  PUT  |  aplikasi/json  | 
|  /v1/pengguna/1  |  DELETE  |  aplikasi/json  | 

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

Untuk membuat GraphQL API di: AWS AppSync
+ Buka AWS AppSync konsol dan pilih **Buat API**.
+ Untuk nama API, ketik`UserData`.
+ Pilih **Skema kustom**.
+ Pilih **Buat**.

 AWS AppSync Konsol membuat API GraphQL baru untuk Anda menggunakan mode autentikasi kunci API. Anda dapat menggunakan konsol untuk mengatur sisa GraphQL API dan menjalankan kueri di atasnya untuk sisa tutorial ini.

## Membuat Skema GraphQL
<a name="creating-a-graphql-schema"></a>

Sekarang Anda memiliki GraphQL API, mari kita buat skema GraphQL. Dari editor skema di AWS AppSync konsol, pastikan skema Anda cocok dengan skema berikut:

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

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

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

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

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

## Konfigurasikan Sumber Data HTTP Anda
<a name="configure-your-http-data-source"></a>

Untuk mengonfigurasi sumber data HTTP Anda, lakukan hal berikut:
+ Pada **DataSources**tab, pilih **Baru**, lalu ketik nama ramah untuk sumber data (misalnya,`HTTP`).
+ Di **tipe sumber data**, pilih **HTTP**.
+ Setel titik akhir ke titik akhir API Gateway yang dibuat. Pastikan Anda tidak menyertakan nama panggung sebagai bagian dari titik akhir.

 **Catatan:** Saat ini hanya titik akhir publik yang didukung oleh AWS AppSync.

 **Catatan:** Untuk informasi selengkapnya tentang otoritas sertifikasi yang diakui oleh AWS AppSync layanan, lihat [Otoritas Sertifikat (CA) yang Diakui oleh AWS AppSync untuk Titik Akhir HTTPS](http-cert-authorities.md#aws-appsync-http-certificate-authorities).

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

Pada langkah ini, Anda menghubungkan sumber data http ke kueri **getUser**.

Untuk mengatur resolver:
+ Pilih tab **Skema**.
+ **Di panel **tipe Data** di sebelah kanan di bawah tipe **Query**, temukan bidang **getUser dan pilih** Lampirkan.**
+ Di **nama sumber data**, pilih **HTTP**.
+ Di **Konfigurasikan templat pemetaan permintaan**, tempel kode berikut:

```
{
    "version": "2018-05-29",
    "method": "GET",
    "params": {
        "headers": {
            "Content-Type": "application/json"
        }
    },
    "resourcePath": $util.toJson("/v1/users/${ctx.args.id}")
}
```
+ Di **Konfigurasikan template pemetaan respons**, tempel kode berikut:

```
## return the body
#if($ctx.result.statusCode == 200)
    ##if response is 200
    $ctx.result.body
#else
    ##if response is not 200, append the response to error block.
    $utils.appendError($ctx.result.body, "$ctx.result.statusCode")
#end
```
+ Pilih tab **Query**, dan kemudian jalankan query berikut:

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

Ini akan mengembalikan respons berikut:

```
{
    "data": {
        "getUser": {
            "id": "1",
            "username": "nadia"
        }
    }
}
```
+ Pilih tab **Skema**.
+ **Di panel **tipe Data** di sebelah kanan bawah **Mutasi**, temukan bidang AddUser dan pilih **Lampirkan**.**
+ Di **nama sumber data**, pilih **HTTP**.
+ Di **Konfigurasikan templat pemetaan permintaan**, tempel kode berikut:

```
{
    "version": "2018-05-29",
    "method": "POST",
    "resourcePath": "/v1/users",
    "params":{
      "headers":{
        "Content-Type": "application/json",
      },
      "body": $util.toJson($ctx.args.userInput)
    }
}
```
+ Di **Konfigurasikan template pemetaan respons**, tempel kode berikut:

```
## Raise a GraphQL field error in case of a datasource invocation error
#if($ctx.error)
    $util.error($ctx.error.message, $ctx.error.type)
#end
## if the response status code is not 200, then return an error. Else return the body **
#if($ctx.result.statusCode == 200)
    ## If response is 200, return the body.
    $ctx.result.body
#else
    ## If response is not 200, append the response to error block.
    $utils.appendError($ctx.result.body, "$ctx.result.statusCode")
#end
```
+ Pilih tab **Query**, dan kemudian jalankan query berikut:

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

Ini akan mengembalikan respons berikut:

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

## Layanan Pemanggilan AWS
<a name="invoking-aws-services"></a>

Anda dapat menggunakan resolver HTTP untuk menyiapkan antarmuka GraphQL API untuk layanan. AWS Permintaan HTTP AWS harus ditandatangani dengan [proses Signature Version 4](https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html) sehingga AWS dapat mengidentifikasi siapa yang mengirimnya. AWS AppSync menghitung tanda tangan atas nama Anda saat Anda mengaitkan peran IAM dengan sumber data HTTP.

Anda menyediakan dua komponen tambahan untuk memanggil AWS layanan dengan resolver HTTP:
+ Peran IAM dengan izin untuk memanggil layanan AWS APIs
+ Konfigurasi penandatanganan di sumber data

Misalnya, jika Anda ingin memanggil [ListGraphqlApis operasi](https://docs.aws.amazon.com/appsync/latest/APIReference/API_ListGraphqlApis.html) dengan resolver HTTP, pertama-tama Anda [membuat peran IAM yang AWS AppSync diasumsikan dengan kebijakan](attaching-a-data-source.md#aws-appsync-getting-started-build-a-schema-from-scratch) berikut yang dilampirkan:

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

****  

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

------

Selanjutnya, buat sumber data HTTP untuk AWS AppSync. Dalam contoh ini, Anda menelepon AWS AppSync di Wilayah Barat AS (Oregon). Siapkan konfigurasi HTTP berikut dalam file bernama`http.json`, yang mencakup wilayah penandatanganan dan nama layanan:

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

Kemudian, gunakan AWS CLI untuk membuat sumber data dengan peran terkait sebagai berikut:

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

Saat Anda melampirkan resolver ke bidang dalam skema, gunakan templat pemetaan permintaan berikut untuk memanggil: AWS AppSync

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

Saat Anda menjalankan kueri GraphQL untuk sumber data ini AWS AppSync , tandatangani permintaan menggunakan peran yang Anda berikan dan menyertakan tanda tangan dalam permintaan. Kueri mengembalikan daftar AWS AppSync APIs GraphQL di akun Anda di Wilayah tersebut. AWS 

# Menggunakan Aurora Serverless v2 dengan AWS AppSync
<a name="tutorial-rds-resolvers"></a>

Hubungkan GraphQL API Anda ke database Aurora Serverless menggunakan. AWS AppSync Integrasi ini memungkinkan Anda mengeksekusi pernyataan SQL melalui kueri, mutasi, dan langganan GraphQL - memberi Anda cara yang fleksibel untuk berinteraksi dengan data relasional Anda.

**catatan**  
Tutorial ini menggunakan Wilayah `US-EAST-1`.

**Manfaat**
+ Integrasi mulus antara GraphQL dan database relasional
+ Kemampuan untuk melakukan operasi SQL melalui antarmuka GraphQL
+ Skalabilitas tanpa server dengan Aurora Serverless v2
+ Akses data aman melalui AWS Secrets Manager
+ Perlindungan terhadap injeksi SQL melalui sanitasi input
+ Kemampuan kueri yang fleksibel termasuk operasi penyaringan dan jangkauan

**Kasus Penggunaan Umum**
+ Membangun aplikasi yang dapat diskalakan dengan persyaratan data relasional
+ Membuat APIs yang membutuhkan fleksibilitas GraphQL dan kemampuan database SQL
+ Mengelola operasi data melalui mutasi dan kueri GraphQL
+ Menerapkan pola akses database yang aman

Dalam tutorial ini, Anda akan mempelajari yang berikut ini.
+ Siapkan cluster v2 Aurora Tanpa Server
+ Aktifkan fungsionalitas API Data
+ Membuat dan mengkonfigurasi struktur database
+ Tentukan skema GraphQL untuk operasi database
+ Menerapkan resolver untuk kueri dan mutasi
+ Amankan akses data Anda melalui sanitasi input yang tepat
+ Jalankan berbagai operasi database melalui antarmuka GraphQL

**Topics**
+ [Menyiapkan kluster database Anda](#create-cluster)
+ [Aktifkan API Data](#enable-data-api)
+ [Buat database dan tabel](#create-database-and-table)
+ [GraphQL skema](#graphql-schema)
+ [Hubungkan API Anda ke Operasi Database](#configuring-resolvers)
+ [Ubah Data Anda Melalui API](#run-mutations)
+ [Ambil Data Anda](#run-queries)
+ [Amankan Akses Data Anda](#input-sanitization)

## Menyiapkan kluster database Anda
<a name="create-cluster"></a>

Sebelum menambahkan sumber data Amazon RDS AWS AppSync, Anda harus terlebih dahulu mengaktifkan API Data pada klaster v2 Aurora Tanpa Server **dan** mengonfigurasi rahasia menggunakan. *AWS Secrets Manager* Anda dapat membuat cluster Aurora Serverless v2 menggunakan: AWS CLI

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

Ini akan mengembalikan ARN untuk cluster.

Setelah membuat cluster, Anda harus menambahkan instance Aurora Serverless v2 menggunakan perintah berikut.

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

**catatan**  
Titik akhir ini membutuhkan waktu untuk diaktifkan. Anda dapat memeriksa statusnya di konsol Amazon RDS di tab **Konektivitas & keamanan** untuk cluster. Anda juga dapat memeriksa status cluster Anda dengan AWS CLI perintah berikut.   

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

Anda dapat membuat *Rahasia* menggunakan AWS Secrets Manager Konsol atau AWS CLI dengan file input seperti berikut menggunakan `USERNAME` dan `COMPLEX_PASSWORD` dari langkah sebelumnya.

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

Berikan ini sebagai parameter ke AWS CLI:

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

Ini akan mengembalikan ARN untuk rahasianya.

 **Perhatikan ARN** cluster Aurora Tanpa Server Anda dan Rahasia untuk digunakan nanti di AppSync konsol saat membuat sumber data.

## Aktifkan API Data
<a name="enable-data-api"></a>

Anda dapat mengaktifkan Data API pada klaster Anda dengan [mengikuti petunjuk dalam dokumentasi RDS](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/data-api.html). Data API harus diaktifkan sebelum menambahkan sebagai sumber AppSync data.

## Buat database dan tabel
<a name="create-database-and-table"></a>

Setelah Anda mengaktifkan API Data Anda, Anda dapat memastikannya berfungsi dengan `aws rds-data execute-statement` perintah di AWS CLI. Ini akan memastikan bahwa cluster Aurora Serverless Anda dikonfigurasi dengan benar sebelum menambahkannya ke API Anda. AppSync Pertama membuat database yang disebut *TESTDB* dengan `--sql` parameter seperti:

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

Jika ini berjalan tanpa kesalahan, tambahkan tabel dengan perintah *create table*:

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

Jika semuanya berjalan tanpa masalah, Anda dapat melanjutkan untuk menambahkan cluster sebagai sumber data di AppSync API Anda.

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

Sekarang setelah Aurora Serverless Data API Anda aktif dan berjalan dengan tabel, kami akan membuat skema GraphQL dan melampirkan resolver untuk melakukan mutasi dan langganan. Buat API baru di AWS AppSync konsol dan arahkan ke halaman **Skema**, lalu masukkan yang berikut ini:

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

input CreatePetInput {
    type: PetType
    price: Float!
}

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

input DeletePetInput {
    id: ID!
}

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

enum PetType {
    dog
    cat
    fish
    bird
    gecko
}

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

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

 **Simpan** skema Anda dan arahkan ke halaman **Sumber Data** dan buat sumber data baru. Pilih **Database relasional** untuk tipe sumber data, dan berikan nama yang ramah. Gunakan nama database yang Anda buat pada langkah terakhir, serta **ARN Cluster** tempat Anda membuatnya. Untuk **Peran**, Anda dapat AppSync membuat peran baru atau membuat peran dengan kebijakan yang mirip dengan di bawah ini:

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

****  

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

------

Perhatikan ada dua **Pernyataan** dalam kebijakan ini yang Anda berikan akses peran. **Sumber daya** pertama adalah cluster Aurora Tanpa Server Anda dan yang kedua adalah ARN Anda. AWS Secrets Manager Anda harus memberikan **KEDUANYA** ARNs dalam konfigurasi sumber AppSync data sebelum mengklik **Buat**.

Lewati ini sebagai parameter ke file AWS CLI.

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

Ini akan mengembalikan ARN untuk rahasianya. Catat ARN cluster Aurora Serverless Anda dan Rahasia untuk nanti saat membuat sumber data di konsol. AWS AppSync 

### Bangun Struktur Database Anda
<a name="create-database-and-table"></a>

Setelah Anda mengaktifkan API Data Anda, Anda dapat memastikannya berfungsi dengan `aws rds-data execute-statement` perintah di AWS CLI. Ini akan memastikan bahwa cluster Aurora Serverless v2 Anda dikonfigurasi dengan benar sebelum menambahkannya ke API Anda. AWS AppSync Pertama, buat database yang disebut *TESTDB* dengan `--sql` parameter sebagai berikut.

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

Jika ini berjalan tanpa kesalahan, tambahkan tabel dengan perintah *create table* berikut.

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

### Rancang Antarmuka API Anda
<a name="graphql-schema"></a>

Setelah Aurora Serverless v2 Data API aktif dan berjalan dengan tabel, buat skema GraphQL dan lampirkan resolver untuk melakukan mutasi dan langganan. Buat API baru di AWS AppSync konsol dan arahkan ke halaman **Skema** di konsol, lalu masukkan yang berikut ini.

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

 **Simpan** skema Anda dan arahkan ke halaman **Sumber Data** dan buat sumber data baru. Pilih **database Relasional** untuk tipe **sumber data**, dan berikan nama yang ramah. Gunakan nama database yang Anda buat pada langkah terakhir, serta **ARN Cluster** tempat Anda membuatnya. Untuk **Peran**, Anda dapat AWS AppSync membuat peran baru atau membuat peran dengan kebijakan yang mirip dengan berikut ini.

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

****  

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

------

Perhatikan ada dua **Pernyataan** dalam kebijakan ini yang Anda berikan akses peran. **Sumber daya** pertama adalah cluster Aurora Serverless v2 Anda dan yang kedua adalah ARN Anda. AWS Secrets Manager Anda harus memberikan **KEDUANYA** ARNs dalam konfigurasi sumber AWS AppSync data sebelum mengklik **Buat**.

## Hubungkan API Anda ke Operasi Database
<a name="configuring-resolvers"></a>

Sekarang kita memiliki skema GraphQL yang valid dan sumber data RDS, Anda dapat melampirkan resolver ke bidang GraphQL ke skema Anda. API kami akan menawarkan kemampuan berikut:

1. buat hewan peliharaan menggunakan bidang *mutation.createPet*

1. perbarui hewan peliharaan menggunakan bidang *mutation.updatePet*

1. hapus hewan peliharaan menggunakan bidang *mutation.deletePet*

1. dapatkan satu menggunakan melalui bidang *Query.getPet*

1. daftar semua menggunakan bidang *Query.listPets*

1. daftar hewan peliharaan dalam kisaran harga menggunakan *Query. listPetsByPriceRange*lapangan

### Mutasi.createPet
<a name="mutation-createpet"></a>

Dari editor skema di AWS AppSync konsol, di sisi kanan pilih **Lampirkan Resolver** untuk. `createPet(input: CreatePetInput!): Pet` Pilih sumber data RDS Anda. Di bagian **template pemetaan permintaan**, tambahkan template berikut:

```
#set($id=$utils.autoId())
{
"version": "2018-05-29",
    "statements": [
        "insert into Pets VALUES (:ID, :TYPE, :PRICE)",
        "select * from Pets WHERE id = :ID"
    ],
    "variableMap": {
        ":ID": "$ctx.args.input.id",
        ":TYPE": $util.toJson($ctx.args.input.type),
        ":PRICE": $util.toJson($ctx.args.input.price)
    }
}
```

**Sistem mengeksekusi pernyataan SQL secara berurutan, berdasarkan urutan dalam array pernyataan.** Hasilnya akan kembali dalam urutan yang sama. Karena ini adalah mutasi, Anda akan menjalankan pernyataan *pilih* setelah *sisipan untuk mengambil nilai yang dikomit* untuk mengisi template pemetaan respons GraphQL.

Di bagian **template pemetaan respons**, tambahkan templat berikut:

```
$utils.toJson($utils.rds.toJsonObject($ctx.result)[1][0])
```

Karena *pernyataan* memiliki dua query SQL, kita perlu menentukan hasil kedua dalam matriks yang kembali dari database dengan:. `$utils.rds.toJsonString($ctx.result))[1][0])`

### mutasi.updatePET
<a name="mutation-updatepet"></a>

Dari editor skema di AWS AppSync konsol, pilih **Lampirkan Resolver** untuk. `updatePet(input: UpdatePetInput!): Pet` Pilih **sumber data RDS** Anda. Di bagian **template pemetaan permintaan**, tambahkan template berikut.

```
{
"version": "2018-05-29",
    "statements": [
        $util.toJson("update Pets set type=:TYPE, price=:PRICE WHERE id=:ID"),
        $util.toJson("select * from Pets WHERE id = :ID")
    ],
    "variableMap": {
        ":ID": "$ctx.args.input.id",
        ":TYPE": $util.toJson($ctx.args.input.type),
        ":PRICE": $util.toJson($ctx.args.input.price)
    }
}
```

Di bagian **template pemetaan respons**, tambahkan template berikut.

```
$utils.toJson($utils.rds.toJsonObject($ctx.result)[1][0])
```

### mutasi.deletePet
<a name="mutation-deletepet"></a>

Dari editor skema di AWS AppSync konsol, pilih **Lampirkan Resolver** untuk. `deletePet(input: DeletePetInput!): Pet` Pilih **sumber data RDS** Anda. Di bagian **template pemetaan permintaan**, tambahkan template berikut.

```
{
"version": "2018-05-29",
    "statements": [
        $util.toJson("select * from Pets WHERE id=:ID"),
        $util.toJson("delete from Pets WHERE id=:ID")
    ],
    "variableMap": {
        ":ID": "$ctx.args.input.id"
    }
}
```

Di bagian **template pemetaan respons**, tambahkan template berikut.

```
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0][0])
```

### Query.getPet
<a name="query-getpet"></a>

Sekarang mutasi dibuat untuk skema Anda, hubungkan tiga kueri untuk menampilkan cara mendapatkan item individual, daftar, dan menerapkan pemfilteran SQL. Dari **editor skema** di AWS AppSync konsol, pilih **Lampirkan Resolver** untuk. `getPet(id: ID!): Pet` Pilih **sumber data RDS** Anda. Di bagian **template pemetaan permintaan**, tambahkan template berikut.

```
{
"version": "2018-05-29",
        "statements": [
            $util.toJson("select * from Pets WHERE id=:ID")
    ],
    "variableMap": {
        ":ID": "$ctx.args.id"
    }
}
```

Di bagian **template pemetaan respons**, tambahkan templat berikut:

```
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0][0])
```

### Query.listpets
<a name="query-listpets"></a>

Dari editor skema di AWS AppSync konsol, di sisi kanan pilih **Lampirkan Resolver** untuk. `getPet(id: ID!): Pet` Pilih **sumber data RDS** Anda. Di bagian **template pemetaan permintaan**, tambahkan template berikut.

```
{
    "version": "2018-05-29",
    "statements": [
        "select * from Pets"
    ]
}
```

Di bagian **template pemetaan respons**, tambahkan template berikut.

```
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])
```

### Permintaan. listPetsByPriceRange
<a name="query-listpetsbypricerange"></a>

Dari editor skema di AWS AppSync konsol, di sisi kanan pilih **Lampirkan Resolver** untuk. `getPet(id: ID!): Pet` Pilih **sumber data RDS** Anda. Di bagian **template pemetaan permintaan**, tambahkan template berikut.

```
{
    "version": "2018-05-29",
    "statements": [
            "select * from Pets where price > :MIN and price < :MAX"
    ],

    "variableMap": {
        ":MAX": $util.toJson($ctx.args.max),
        ":MIN": $util.toJson($ctx.args.min)
    }
}
```

Di bagian **template pemetaan respons**, tambahkan templat berikut:

```
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])
```

## Ubah Data Anda Melalui API
<a name="run-mutations"></a>

Sekarang setelah Anda mengonfigurasi semua resolver Anda dengan pernyataan SQL dan menghubungkan GraphQL API Anda ke API Data Aurora Tanpa Server, Anda dapat mulai melakukan mutasi dan kueri. Di AWS AppSync konsol, pilih tab **Kueri** dan masukkan yang berikut ini untuk membuat Pet:

```
mutation add {
    createPet(input : { type:fish, price:10.0 }){
        id
        type
        price
    }
}
```

Respons harus berisi *id*, *tipe*, dan *harga* seperti:

```
{
  "data": {
    "createPet": {
      "id": "c6fedbbe-57ad-4da3-860a-ffe8d039882a",
      "type": "fish",
      "price": "10.0"
    }
  }
}
```

Anda dapat memodifikasi item ini dengan menjalankan mutasi *updatePet*:

```
mutation update {
    updatePet(input : {
        id: ID_PLACEHOLDER,
        type:bird,
        price:50.0
    }){
        id
        type
        price
    }
}
```

Perhatikan bahwa kami menggunakan *id* yang dikembalikan dari operasi *createPet* sebelumnya. Ini akan menjadi nilai unik untuk catatan Anda saat resolver dimanfaatkan. `$util.autoId()` Anda dapat menghapus catatan dengan cara yang sama:

```
mutation delete {
    deletePet(input : {id:ID_PLACEHOLDER}){
        id
        type
        price
    }
}
```

Buat beberapa catatan dengan mutasi pertama dengan nilai *harga* yang berbeda dan kemudian jalankan beberapa kueri.

## Ambil Data Anda
<a name="run-queries"></a>

Masih di tab **Kueri** konsol, gunakan pernyataan berikut untuk mencantumkan semua catatan yang telah Anda buat.

```
query allpets {
    listPets {
        id
        type
        price
    }
}
```

*Manfaatkan predikat SQL *WHERE* yang ada `where price > :MIN and price < :MAX` di template pemetaan kami untuk Query. listPetsByPriceRange*dengan query GraphQL berikut:

```
query petsByPriceRange {
    listPetsByPriceRange(min:1, max:11) {
        id
        type
        price
    }
}
```

Anda seharusnya hanya melihat catatan dengan *harga* lebih dari \$11 atau kurang dari \$110. Akhirnya, Anda dapat melakukan kueri untuk mengambil catatan individual sebagai berikut:

```
query onePet {
    getPet(id:ID_PLACEHOLDER){
        id
        type
        price
    }
}
```

## Amankan Akses Data Anda
<a name="input-sanitization"></a>

Injeksi SQL adalah kerentanan keamanan dalam aplikasi database. Itu terjadi ketika penyerang memasukkan kode SQL berbahaya melalui bidang input pengguna. Ini dapat memungkinkan akses tidak sah ke data database. Kami menyarankan Anda memvalidasi dan membersihkan semua input pengguna dengan hati-hati sebelum memproses penggunaan `variableMap` untuk perlindungan terhadap serangan injeksi SQL. Jika peta variabel tidak digunakan, Anda bertanggung jawab untuk membersihkan argumen operasi GraphQL mereka. Salah satu cara untuk melakukannya adalah dengan memberikan input langkah-langkah validasi spesifik dalam template pemetaan permintaan sebelum eksekusi pernyataan SQL terhadap API Data Anda. Mari kita lihat bagaimana kita dapat memodifikasi template pemetaan permintaan dari `listPetsByPriceRange` contoh. Alih-alih hanya mengandalkan input pengguna, Anda dapat melakukan hal berikut:

```
#set($validMaxPrice = $util.matches("\d{1,3}[,\\.]?(\\d{1,2})?",$ctx.args.maxPrice))

#set($validMinPrice = $util.matches("\d{1,3}[,\\.]?(\\d{1,2})?",$ctx.args.minPrice))


#if (!$validMaxPrice || !$validMinPrice)
    $util.error("Provided price input is not valid.")
#end
{
    "version": "2018-05-29",
    "statements": [
            "select * from Pets where price > :MIN and price < :MAX"
    ],

    "variableMap": {
        ":MAX": $util.toJson($ctx.args.maxPrice),
        ":MIN": $util.toJson($ctx.args.minPrice)
    }
}
```

Cara lain untuk melindungi terhadap masukan jahat saat mengeksekusi resolver terhadap API Data Anda adalah dengan menggunakan pernyataan yang disiapkan bersama dengan prosedur tersimpan dan input berparameter. Misalnya, dalam resolver untuk `listPets` menentukan prosedur berikut yang mengeksekusi *pilih* sebagai pernyataan yang disiapkan:

```
CREATE PROCEDURE listPets (IN type_param VARCHAR(200))
  BEGIN
     PREPARE stmt FROM 'SELECT * FROM Pets where type=?';
     SET @type = type_param;
     EXECUTE stmt USING @type;
     DEALLOCATE PREPARE stmt;
  END
```

Buat ini di Instans Aurora Serverless v2 Anda.

```
aws rds-data execute-statement --resource-arn "arn:aws:rds:us-east-1:xxxxxxxxxxxx:cluster:http-endpoint-test" \
--schema "mysql"  --secret-arn "arn:aws:secretsmanager:us-east-1:xxxxxxxxxxxx:secret:httpendpoint-xxxxxx"  \
--region us-east-1  --database "DB_NAME" \
--sql "CREATE PROCEDURE listPets (IN type_param VARCHAR(200)) BEGIN PREPARE stmt FROM 'SELECT * FROM Pets where type=?'; SET @type = type_param; EXECUTE stmt USING @type; DEALLOCATE PREPARE stmt; END"
```

Kode resolver yang dihasilkan untuk ListPets disederhanakan karena kita sekarang cukup memanggil prosedur tersimpan. Minimal, setiap input string harus memiliki tanda kutip tunggal yang [lolos.](#escaped)

```
#set ($validType = $util.isString($ctx.args.type) && !$util.isNullOrBlank($ctx.args.type))
#if (!$validType)
    $util.error("Input for 'type' is not valid.", "ValidationError")
#end

{
    "version": "2018-05-29",
    "statements": [
        "CALL listPets(:type)"
    ]
    "variableMap": {
        ":type": $util.toJson($ctx.args.type.replace("'", "''"))
    }
}
```

### Menggunakan string pelarian
<a name="escaped"></a>

Gunakan tanda kutip tunggal untuk menandai awal dan akhir literal string dalam pernyataan SQL misalnya.. `'some string value'`. Untuk memungkinkan nilai string dengan satu atau lebih karakter kutipan tunggal (`'`) untuk digunakan dalam string, masing-masing harus diganti dengan dua tanda kutip tunggal (`''`). Misalnya, jika string inputnya`Nadia's dog`, Anda akan menghindarinya untuk pernyataan SQL seperti

```
update Pets set type='Nadia''s dog' WHERE id='1'
```

# Menggunakan resolver pipa di AWS AppSync
<a name="tutorial-pipeline-resolvers"></a>

**catatan**  
Kami sekarang terutama mendukung runtime APPSYNC\$1JS dan dokumentasinya. [Harap pertimbangkan untuk menggunakan runtime APPSYNC\$1JS dan panduannya di sini.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

AWS AppSync menyediakan cara sederhana untuk menghubungkan bidang GraphQL ke sumber data tunggal melalui resolver unit. Namun, menjalankan satu operasi mungkin tidak cukup. Pipeline resolvers menawarkan kemampuan untuk menjalankan operasi secara serial terhadap sumber data. Buat fungsi di API Anda dan lampirkan ke resolver pipeline. Setiap hasil eksekusi fungsi disalurkan ke yang berikutnya sampai tidak ada fungsi yang tersisa untuk dieksekusi. Dengan resolver pipeline, Anda sekarang dapat membangun alur kerja yang lebih kompleks secara langsung. AWS AppSync Dalam tutorial ini, Anda membangun aplikasi tampilan gambar sederhana, di mana pengguna dapat memposting dan melihat gambar yang diposting oleh teman-teman mereka.

## Pengaturan Satu-Klik
<a name="one-click-setup"></a>

Jika Anda ingin secara otomatis mengatur titik akhir AWS AppSync GraphQL dengan semua resolver yang dikonfigurasi dan sumber daya yang AWS diperlukan, Anda dapat menggunakan templat berikut: AWS CloudFormation 

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

Tumpukan ini membuat sumber daya berikut di akun Anda:
+ Peran IAM AWS AppSync untuk mengakses sumber daya di akun Anda
+ 2 tabel DynamoDB
+ 1 kumpulan pengguna Amazon Cognito
+ 2 grup kumpulan pengguna Amazon Cognito
+ 3 pengguna kumpulan pengguna Amazon Cognito
+ 1 AWS AppSync API

Di akhir proses pembuatan AWS CloudFormation tumpukan, Anda menerima satu email untuk masing-masing dari tiga pengguna Amazon Cognito yang dibuat. Setiap email berisi kata sandi sementara yang Anda gunakan untuk masuk sebagai pengguna Amazon Cognito ke konsol. AWS AppSync Simpan kata sandi untuk sisa tutorial.

## Pengaturan Manual
<a name="manual-setup"></a>

Jika Anda lebih suka melalui step-by-step proses secara manual melalui AWS AppSync konsol, ikuti proses pengaturan di bawah ini.

### Menyiapkan Non AWS AppSync Sumber Daya Anda
<a name="setting-up-your-non-aws-appsync-resources"></a>

API berkomunikasi dengan dua tabel DynamoDB: tabel gambar **yang** menyimpan gambar dan tabel teman **yang** menyimpan hubungan antar pengguna. API dikonfigurasi untuk menggunakan kumpulan pengguna Amazon Cognito sebagai jenis otentikasi. CloudFormation Tumpukan berikut mengatur sumber daya ini di akun.

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

Di akhir proses pembuatan AWS CloudFormation tumpukan, Anda menerima satu email untuk masing-masing dari tiga pengguna Amazon Cognito yang dibuat. Setiap email berisi kata sandi sementara yang Anda gunakan untuk masuk sebagai pengguna Amazon Cognito ke konsol. AWS AppSync Simpan kata sandi untuk sisa tutorial.

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

Untuk membuat GraphQL API di: AWS AppSync

1. Buka AWS AppSync konsol dan pilih **Build From Scratch** dan pilih **Start**.

1. Tetapkan nama API ke`AppSyncTutorial-PicturesViewer`.

1. Pilih **Buat**.

 AWS AppSync Konsol membuat API GraphQL baru untuk Anda menggunakan mode autentikasi kunci API. Anda dapat menggunakan konsol untuk mengatur sisa GraphQL API dan menjalankan kueri terhadapnya selama sisa tutorial ini.

### Mengkonfigurasi API GraphQL
<a name="configuring-the-graphql-api"></a>

Anda perlu mengonfigurasi AWS AppSync API dengan kumpulan pengguna Amazon Cognito yang baru saja Anda buat.

1. Pilih tab **Pengaturan**.

1. Di bawah bagian **Jenis Otorisasi**, pilih Kumpulan Pengguna *Amazon Cognito*.

1. *Di bawah **Konfigurasi Pool Pengguna**, pilih **US-WEST-2 untuk Wilayah**.AWS *

1. Pilih **AppSyncTutorial-** kumpulan UserPool pengguna.

1. Pilih **DENY** sebagai *Default Action*.

1. Biarkan bidang **regex AppId klien** kosong.

1. Pilih **Simpan**.

API sekarang disiapkan untuk menggunakan kumpulan pengguna Amazon Cognito sebagai jenis otorisasi.

### Mengkonfigurasi Sumber Data untuk Tabel DynamoDB
<a name="configuring-data-sources-for-the-ddb-tables"></a>

**Setelah tabel DynamoDB dibuat, navigasikan ke AWS AppSync GraphQL API Anda di konsol dan pilih tab Sumber Data.** Sekarang, Anda akan membuat sumber data AWS AppSync untuk setiap tabel DynamoDB yang baru saja Anda buat.

1. Pilih tab **Sumber data**.

1. Pilih **Baru** untuk membuat sumber data baru.

1. Untuk nama sumber data, masukkan`PicturesDynamoDBTable`.

1. Untuk tipe sumber data, pilih tabel **Amazon DynamoDB**.

1. Untuk wilayah, pilih **US-WEST-2**.

1. Dari daftar tabel, pilih tabel **AppSyncTutorial-Pictures** DynamoDB.

1. Di bagian **Buat atau gunakan peran yang ada**, pilih **Peran yang ada**.

1. Pilih peran yang baru saja dibuat dari CloudFormation template. Jika Anda tidak mengubah *ResourceNamePrefix*, nama peran harus **AppSyncTutorialDBRole-Dynamo**.

1. Pilih **Buat**.

Ulangi proses yang sama untuk tabel **teman**, nama tabel DynamoDB **AppSyncTutorialharus** -Friends jika Anda tidak mengubah parameter *ResourceNamePrefix*pada saat membuat tumpukan. CloudFormation 

### Membuat Skema GraphQL
<a name="creating-the-graphql-schema"></a>

Sekarang sumber data terhubung ke tabel DynamoDB Anda, mari buat skema GraphQL. Dari editor skema di AWS AppSync konsol, pastikan skema Anda cocok dengan skema berikut:

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

type Mutation {
    createPicture(input: CreatePictureInput!): Picture!
    @aws_auth(cognito_groups: ["Admins"])
    createFriendship(id: ID!, target: ID!): Boolean
    @aws_auth(cognito_groups: ["Admins"])
}

type Query {
    getPicturesByOwner(id: ID!): [Picture]
    @aws_auth(cognito_groups: ["Admins", "Viewers"])
}

type Picture {
    id: ID!
    owner: ID!
    src: String
}

input CreatePictureInput {
    owner: ID!
    src: String!
}
```

Pilih **Simpan Skema** untuk menyimpan skema Anda.

*Beberapa bidang skema telah dianotasi dengan direktif @aws\$1auth.* Karena konfigurasi tindakan default API disetel ke *DENY*, API menolak semua pengguna yang bukan anggota grup yang disebutkan di dalam direktif *@aws\$1auth*. Untuk informasi selengkapnya tentang cara mengamankan API, Anda dapat membaca halaman [Keamanan](security-authz.md#aws-appsync-security). **Dalam hal ini, hanya pengguna admin yang memiliki akses ke bidang *mutation.createPicture dan mutation.createFriendship**, sementara pengguna yang merupakan anggota grup Admin atau Pemirsa* dapat mengakses Kueri.** * getPicturesByBidang pemilik*. Semua pengguna lain tidak memiliki akses.

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

Sekarang Anda memiliki skema GraphQL yang valid dan dua sumber data, Anda dapat melampirkan resolver ke bidang GraphQL pada skema. API menawarkan kemampuan berikut:
+ Buat gambar melalui bidang *mutation.createPicture*
+ Buat pertemanan melalui bidang *mutation.createFriendship*
+ Mengambil gambar melalui bidang *Query.getPicture*

#### mutasi.createPicture
<a name="mutation-createpicture"></a>

Dari editor skema di AWS AppSync konsol, di sisi kanan pilih **Lampirkan Resolver** untuk. `createPicture(input: CreatePictureInput!): Picture!` Pilih sumber data *PicturesDynamoDBTable*DynamoDB. Di bagian **template pemetaan permintaan**, tambahkan template berikut:

```
#set($id = $util.autoId())

{
    "version" : "2018-05-29",

    "operation" : "PutItem",

    "key" : {
        "id" : $util.dynamodb.toDynamoDBJson($id),
        "owner": $util.dynamodb.toDynamoDBJson($ctx.args.input.owner)
    },

    "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args.input)
}
```

Di bagian **template pemetaan respons**, tambahkan templat berikut:

```
#if($ctx.error)
    $util.error($ctx.error.message, $ctx.error.type)
#end
$util.toJson($ctx.result)
```

Fungsionalitas membuat gambar selesai. Anda menyimpan gambar di tabel **Gambar**, menggunakan UUID yang dihasilkan secara acak sebagai id gambar, dan menggunakan nama pengguna Cognito sebagai pemilik gambar.

#### mutation.createFriendship
<a name="mutation-createfriendship"></a>

Dari editor skema di AWS AppSync konsol, di sisi kanan pilih **Lampirkan Resolver** untuk. `createFriendship(id: ID!, target: ID!): Boolean` Pilih sumber data **FriendsDynamoDBTable**DynamoDB. Di bagian **template pemetaan permintaan**, tambahkan template berikut:

```
#set($userToFriendFriendship = { "userId" : "$ctx.args.id", "friendId": "$ctx.args.target" })
#set($friendToUserFriendship = { "userId" : "$ctx.args.target", "friendId": "$ctx.args.id" })
#set($friendsItems = [$util.dynamodb.toMapValues($userToFriendFriendship), $util.dynamodb.toMapValues($friendToUserFriendship)])

{
    "version" : "2018-05-29",
    "operation" : "BatchPutItem",
    "tables" : {
        ## Replace 'AppSyncTutorial-' default below with the ResourceNamePrefix you provided in the CloudFormation template
        "AppSyncTutorial-Friends": $util.toJson($friendsItems)
    }
}
```

Penting: Dalam template **BatchPutItem**permintaan, nama yang tepat dari tabel DynamoDB harus ada. Nama tabel default adalah *AppSyncTutorial-Friends*. Jika Anda menggunakan nama tabel yang salah, Anda mendapatkan kesalahan saat AppSync mencoba mengambil peran yang disediakan.

Demi kesederhanaan dalam tutorial ini, lanjutkan seolah-olah permintaan pertemanan telah disetujui dan simpan entri hubungan langsung ke **AppSyncTutorialFriends**tabel.

Secara efektif, Anda menyimpan dua item untuk setiap pertemanan karena hubungan itu dua arah. Untuk detail selengkapnya tentang praktik terbaik Amazon DynamoDB untuk many-to-many mewakili hubungan, lihat Praktik Terbaik [DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/bp-adjacency-graphs.html).

Di bagian **template pemetaan respons**, tambahkan templat berikut:

```
#if($ctx.error)
    $util.error($ctx.error.message, $ctx.error.type)
#end
true
```

Catatan: Pastikan template permintaan Anda berisi nama tabel yang tepat. Nama default adalah *AppSyncTutorial-Friends*, tetapi nama tabel Anda mungkin berbeda jika Anda mengubah CloudFormation **ResourceNamePrefix**parameter.

#### Permintaan. getPicturesByPemilik
<a name="query-getpicturesbyowner"></a>

Sekarang setelah Anda memiliki pertemanan dan gambar, Anda perlu memberikan kemampuan bagi pengguna untuk melihat foto teman-teman mereka. Untuk memenuhi persyaratan ini, Anda harus terlebih dahulu memeriksa apakah pemohon berteman dengan pemilik, dan akhirnya meminta gambar.

Karena fungsi ini memerlukan dua operasi sumber data, Anda akan membuat dua fungsi. Fungsi pertama, **IsFriend**, memeriksa apakah pemohon dan pemiliknya adalah teman. Fungsi kedua, **getPicturesByOwner**, mengambil gambar yang diminta diberikan ID pemilik. *Mari kita lihat alur eksekusi di bawah ini untuk resolver yang diusulkan pada Query. getPicturesByBidang pemilik*:

1. Sebelum memetakan template: Siapkan konteks dan argumen masukan bidang.

1. Fungsi isFriend: Memeriksa apakah pemohon adalah pemilik gambar. Jika tidak, ia memeriksa apakah pengguna pemohon dan pemilik adalah teman dengan melakukan operasi GetItem DynamoDB di meja teman.

1. getPicturesBy*Fungsi pemilik: Mengambil gambar dari tabel Gambar menggunakan operasi Query DynamoDB pada indeks pemilik Indeks Sekunder Global.*

1. Setelah memetakan template: Hasil gambar peta sehingga DynamoDB mengatribusikan peta dengan benar ke bidang tipe GraphQL yang diharapkan.

Pertama mari kita buat fungsinya.

##### Fungsi isFriend
<a name="isfriend-function"></a>

1. Pilih tab **Fungsi**.

1. Pilih **Create Function** untuk membuat fungsi.

1. Untuk nama sumber data, masukkan`FriendsDynamoDBTable`.

1. Untuk nama fungsi, masukkan *isFriend*.

1. Di dalam area teks template pemetaan permintaan, tempel template berikut:

   ```
   #set($ownerId = $ctx.prev.result.owner)
   #set($callerId = $ctx.prev.result.callerId)
   
   ## if the owner is the caller, no need to make the check
   #if($ownerId == $callerId)
       #return($ctx.prev.result)
   #end
   
   {
       "version" : "2018-05-29",
   
       "operation" : "GetItem",
   
       "key" : {
           "userId" : $util.dynamodb.toDynamoDBJson($callerId),
           "friendId" : $util.dynamodb.toDynamoDBJson($ownerId)
       }
   }
   ```

1. Di dalam area teks template pemetaan respons, tempel template berikut:

   ```
   #if($ctx.error)
       $util.error("Unable to retrieve friend mapping message: ${ctx.error.message}", $ctx.error.type)
   #end
   
   ## if the users aren't friends
   #if(!$ctx.result)
       $util.unauthorized()
   #end
   
   $util.toJson($ctx.prev.result)
   ```

1. Pilih **Buat Fungsi**.

Hasil: Anda telah membuat fungsi **isFriend**.

##### getPicturesByFungsi pemilik
<a name="getpicturesbyowner-function"></a>

1. Pilih tab **Fungsi**.

1. Pilih **Create Function** untuk membuat fungsi.

1. Untuk nama sumber data, masukkan`PicturesDynamoDBTable`.

1. Untuk nama fungsi, masukkan`getPicturesByOwner`.

1. Di dalam area teks template pemetaan permintaan, tempel template berikut:

   ```
   {
       "version" : "2018-05-29",
   
       "operation" : "Query",
   
       "query" : {
           "expression": "#owner = :owner",
           "expressionNames": {
               "#owner" : "owner"
           },
           "expressionValues" : {
               ":owner" : $util.dynamodb.toDynamoDBJson($ctx.prev.result.owner)
           }
       },
   
       "index": "owner-index"
   }
   ```

1. Di dalam area teks template pemetaan respons, tempel template berikut:

   ```
   #if($ctx.error)
       $util.error($ctx.error.message, $ctx.error.type)
   #end
   
   $util.toJson($ctx.result)
   ```

1. Pilih **Buat Fungsi**.

Hasil: Anda telah membuat fungsi **getPicturesByOwner**. *Sekarang fungsi telah dibuat, lampirkan resolver pipeline ke Query. getPicturesByBidang pemilik*.

Dari editor skema di AWS AppSync konsol, di sisi kanan pilih **Lampirkan Resolver** untuk. `Query.getPicturesByOwner(id: ID!): [Picture]` Pada halaman berikut, pilih tautan **Convert to pipeline resolver** yang muncul di bawah daftar drop-down sumber data. Gunakan yang berikut ini untuk template sebelum pemetaan:

```
#set($result = { "owner": $ctx.args.id, "callerId": $ctx.identity.username })
$util.toJson($result)
```

Di bagian **template setelah pemetaan**, gunakan yang berikut ini:

```
#foreach($picture in $ctx.result.items)
    ## prepend "src://" to picture.src property
    #set($picture['src'] = "src://${picture['src']}")
#end
$util.toJson($ctx.result.items)
```

Pilih **Buat Resolver**. Anda telah berhasil memasang resolver pipa pertama Anda. Pada halaman yang sama, tambahkan dua fungsi yang Anda buat sebelumnya. Di bagian fungsi, pilih **Tambahkan Fungsi** dan kemudian pilih atau ketik nama fungsi pertama, **IsFriend**. Tambahkan fungsi kedua dengan mengikuti proses yang sama untuk fungsi **getPicturesByPemilik**. Pastikan fungsi **isFriend** muncul pertama kali dalam daftar diikuti oleh fungsi **getPicturesByOwner**. Anda dapat menggunakan panah atas dan bawah untuk mengatur ulang urutan pelaksanaan fungsi dalam pipa.

Sekarang setelah pipeline resolver dibuat dan Anda telah melampirkan fungsinya, mari kita uji GraphQL API yang baru dibuat.

## Menguji GraphQL API
<a name="testing-your-graphql-api"></a>

Pertama, Anda perlu mengisi gambar dan pertemanan dengan mengeksekusi beberapa mutasi menggunakan pengguna admin yang Anda buat. Di sisi kiri AWS AppSync konsol, pilih tab **Kueri.**

### Mutasi CreatePicture
<a name="createpicture-mutation"></a>

1. Di AWS AppSync konsol, pilih tab **Kueri**.

1. Pilih **Login Dengan User Pools**.

1. Pada modal, masukkan Cognito Sample Client ID yang dibuat oleh CloudFormation stack misalnya, 37solo6mmhh7k4v63cqdfgdg5d).

1. Masukkan nama pengguna yang Anda berikan sebagai parameter ke CloudFormation tumpukan. Defaultnya adalah **nadia**.

1. Gunakan kata sandi sementara yang dikirim ke email yang Anda berikan sebagai parameter ke CloudFormation tumpukan (misalnya, *UserPoolUserEmail*).

1. Pilih Login. Anda sekarang akan melihat tombol berganti nama menjadi **Logout nadia**, atau nama pengguna apa pun yang Anda pilih saat membuat CloudFormation tumpukan (yaitu,). *UserPoolUsername*

Mari kita kirim beberapa mutasi *CreatePicture* untuk mengisi tabel gambar. Jalankan query GraphQL berikut di dalam konsol:

```
mutation {
  createPicture(input:{
    owner: "nadia"
    src: "nadia.jpg"
  }) {
    id
    owner
    src
  }
}
```

Responsnya akan terlihat seperti di bawah ini:

```
{
  "data": {
    "createPicture": {
      "id": "c6fedbbe-57ad-4da3-860a-ffe8d039882a",
      "owner": "nadia",
      "src": "nadia.jpg"
    }
  }
}
```

Mari tambahkan beberapa gambar lagi:

```
mutation {
  createPicture(input:{
    owner: "shaggy"
    src: "shaggy.jpg"
  }) {
    id
    owner
    src
  }
}
```

```
mutation {
  createPicture(input:{
    owner: "rex"
    src: "rex.jpg"
  }) {
    id
    owner
    src
  }
}
```

Anda telah menambahkan tiga gambar menggunakan **nadia** sebagai pengguna admin.

### Mutasi CreateFriendship
<a name="createfriendship-mutation"></a>

Mari tambahkan entri persahabatan. Jalankan mutasi berikut di konsol.

Catatan: Anda masih harus masuk sebagai pengguna admin (pengguna admin default adalah **nadia**).

```
mutation {
  createFriendship(id: "nadia", target: "shaggy")
}
```

Responsnya akan terlihat seperti:

```
{
  "data": {
    "createFriendship": true
  }
}
```

 **Nadia** dan **shaggy** adalah teman. **Rex** tidak berteman dengan siapa pun.

### getPicturesByKueri Pemilik
<a name="getpicturesbyowner-query"></a>

Untuk langkah ini, masuk sebagai pengguna **nadia** menggunakan Cognito User Pools, menggunakan kredensil yang diatur di awal tutorial ini. **Sebagai **nadia**, ambil foto-foto yang dimiliki oleh shaggy.**

```
query {
    getPicturesByOwner(id: "shaggy") {
        id
        owner
        src
    }
}
```

Karena **nadia** dan **shaggy** adalah teman, kueri harus mengembalikan gambar yang sesuai.

```
{
  "data": {
    "getPicturesByOwner": [
      {
        "id": "05a16fba-cc29-41ee-a8d5-4e791f4f1079",
        "owner": "shaggy",
        "src": "src://shaggy.jpg"
      }
    ]
  }
}
```

Demikian pula, jika **nadia** mencoba mengambil fotonya sendiri, itu juga berhasil. Pipeline resolver telah dioptimalkan untuk menghindari menjalankan GetItem operasi **IsFriend** dalam kasus itu. Coba kueri berikut:

```
query {
    getPicturesByOwner(id: "nadia") {
        id
        owner
        src
    }
}
```

Jika Anda mengaktifkan logging pada API Anda (di panel **Pengaturan**), mengatur tingkat debug ke **ALL**, dan menjalankan kueri yang sama lagi, itu akan mengembalikan log untuk eksekusi bidang. Dengan melihat log, Anda dapat menentukan apakah fungsi **isFriend kembali lebih awal pada tahap Template** **Pemetaan Permintaan**:

```
{
  "errors": [],
  "mappingTemplateType": "Request Mapping",
  "path": "[getPicturesByOwner]",
  "resolverArn": "arn:aws:appsync:us-west-2:XXXX:apis/XXXX/types/Query/fields/getPicturesByOwner",
  "functionArn": "arn:aws:appsync:us-west-2:XXXX:apis/XXXX/functions/o2f42p2jrfdl3dw7s6xub2csdfs",
  "functionName": "isFriend",
  "earlyReturnedValue": {
    "owner": "nadia",
    "callerId": "nadia"
  },
  "context": {
    "arguments": {
      "id": "nadia"
    },
    "prev": {
      "result": {
        "owner": "nadia",
        "callerId": "nadia"
      }
    },
    "stash": {},
    "outErrors": []
  },
  "fieldInError": false
}
```

*earlyReturnedValue*Kunci mewakili data yang dikembalikan oleh direktif *\$1return*.

****Akhirnya, meskipun **rex** adalah anggota Grup UserPool Cognito **Pemirsa**, dan **karena** rex tidak berteman dengan siapa pun, dia tidak akan dapat mengakses salah satu gambar yang dimiliki oleh shaggy atau nadia.**** Jika Anda masuk sebagai **rex** di konsol dan menjalankan kueri berikut:

```
query {
    getPicturesByOwner(id: "nadia") {
        id
        owner
        src
    }
}
```

Anda mendapatkan kesalahan tidak sah berikut:

```
{
  "data": {
    "getPicturesByOwner": null
  },
  "errors": [
    {
      "path": [
        "getPicturesByOwner"
      ],
      "data": null,
      "errorType": "Unauthorized",
      "errorInfo": null,
      "locations": [
        {
          "line": 2,
          "column": 9,
          "sourceName": null
        }
      ],
      "message": "Not Authorized to access getPicturesByOwner on type Query"
    }
  ]
}
```

Anda telah berhasil menerapkan otorisasi kompleks menggunakan resolver pipa.

# Menggunakan operasi Delta Sync pada sumber data berversi di AWS AppSync
<a name="tutorial-delta-sync"></a>

**catatan**  
Kami sekarang terutama mendukung runtime APPSYNC\$1JS dan dokumentasinya. [Harap pertimbangkan untuk menggunakan runtime APPSYNC\$1JS dan panduannya di sini.](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html)

Aplikasi klien dalam AWS AppSync menyimpan data dengan menyimpan respons GraphQL secara lokal ke disk dalam aplikasi. mobile/web Sumber dan `Sync` operasi data berversi memberi pelanggan kemampuan untuk melakukan proses sinkronisasi menggunakan resolver tunggal. Ini memungkinkan klien untuk menghidrasi cache lokal mereka dengan hasil dari satu kueri dasar yang mungkin memiliki banyak catatan, dan kemudian hanya menerima data yang diubah sejak kueri terakhir mereka (pembaruan *delta*). Dengan mengizinkan klien untuk melakukan hidrasi dasar cache dengan permintaan awal dan pembaruan tambahan di tempat lain, Anda dapat memindahkan perhitungan dari aplikasi klien Anda ke backend. Ini jauh lebih efisien untuk aplikasi klien yang sering beralih antara status online dan offline.

Untuk mengimplementasikan Delta Sync, `Sync` kueri menggunakan `Sync` operasi pada sumber data berversi. Ketika AWS AppSync mutasi mengubah item dalam sumber data berversi, catatan perubahan itu akan disimpan di tabel *Delta* juga. Anda dapat memilih untuk menggunakan tabel *Delta* yang berbeda (misalnya satu per jenis, satu per area domain) untuk sumber data berversi lainnya atau tabel *Delta* tunggal untuk API Anda. AWS AppSync merekomendasikan untuk tidak menggunakan tabel *Delta* tunggal untuk beberapa APIs untuk menghindari tabrakan kunci utama.

Selain itu, klien Delta Sync juga dapat menerima langganan sebagai argumen, dan kemudian klien mengoordinasikan langganan menghubungkan kembali dan menulis antara transisi offline ke online. Delta Sync melakukan ini dengan melanjutkan langganan secara otomatis (termasuk backoff eksponensial dan coba lagi dengan jitter melalui skenario kesalahan jaringan yang berbeda), dan menyimpan peristiwa dalam antrian. Kueri delta atau basis yang sesuai kemudian dijalankan sebelum menggabungkan peristiwa apa pun dari antrian, dan akhirnya memproses langganan seperti biasa.

Dokumentasi untuk opsi konfigurasi klien, termasuk Amplify DataStore, tersedia di situs web [Amplify](https://aws-amplify.github.io/) Framework. Dokumentasi ini menguraikan cara mengatur sumber `Sync` dan operasi data DynamoDB berversi untuk bekerja dengan klien Delta Sync untuk akses data yang optimal.

## Pengaturan Satu-Klik
<a name="one-click-setup"></a>

Untuk secara otomatis mengatur titik akhir AWS AppSync GraphQL dengan semua resolver yang dikonfigurasi dan sumber daya yang diperlukan, gunakan templat ini AWS : AWS CloudFormation 

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

Tumpukan ini membuat sumber daya berikut di akun Anda:
+ 2 tabel DynamoDB (Basis dan Delta)
+ 1 AWS AppSync API dengan kunci API
+ 1 Peran IAM dengan kebijakan untuk tabel DynamoDB

Dua tabel digunakan untuk mempartisi kueri sinkronisasi Anda ke tabel kedua yang bertindak sebagai jurnal peristiwa yang tidak terjawab saat klien sedang offline. Untuk menjaga agar kueri tetap efisien pada tabel delta, [Amazon TTLs DynamoDB](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/TTL.html) digunakan untuk secara otomatis mengatur acara seperlunya. Waktu TTL dapat dikonfigurasi untuk kebutuhan Anda pada sumber data (Anda mungkin menginginkan ini sebagai 1 jam, 1 hari, dll.).

## Skema
<a name="schema"></a>

Untuk mendemonstrasikan Delta Sync, aplikasi sampel membuat skema *Posts* yang didukung oleh tabel *Base* dan *Delta* di DynamoDB. AWS AppSync secara otomatis menulis mutasi ke kedua tabel. Kueri sinkronisasi menarik catatan dari tabel *Base* atau *Delta* sebagaimana mestinya, dan satu langganan didefinisikan untuk menunjukkan bagaimana klien dapat memanfaatkan ini dalam logika rekoneksi mereka.

```
input CreatePostInput {
    author: String!
    title: String!
    content: String!
    url: String
    ups: Int
    downs: Int
    _version: Int
}

interface Connection {
  nextToken: String
  startedAt: AWSTimestamp!
}

type Mutation {
    createPost(input: CreatePostInput!): Post
    updatePost(input: UpdatePostInput!): Post
    deletePost(input: DeletePostInput!): Post
}

type Post {
    id: ID!
    author: String!
    title: String!
    content: String!
    url: AWSURL
    ups: Int
    downs: Int
    _version: Int
    _deleted: Boolean
    _lastChangedAt: AWSTimestamp!
}

type PostConnection implements Connection {
    items: [Post!]!
    nextToken: String
    startedAt: AWSTimestamp!
}

type Query {
    getPost(id: ID!): Post
    syncPosts(limit: Int, nextToken: String, lastSync: AWSTimestamp): PostConnection!
}

type Subscription {
    onCreatePost: Post
        @aws_subscribe(mutations: ["createPost"])
    onUpdatePost: Post
        @aws_subscribe(mutations: ["updatePost"])
    onDeletePost: Post
        @aws_subscribe(mutations: ["deletePost"])
}

input DeletePostInput {
    id: ID!
    _version: Int!
}

input UpdatePostInput {
    id: ID!
    author: String
    title: String
    content: String
    url: String
    ups: Int
    downs: Int
    _version: Int!
}

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

Skema GraphQL adalah standar, tetapi beberapa hal layak dipanggil sebelum bergerak maju. Pertama, semua mutasi secara otomatis pertama menulis ke tabel *Base* dan kemudian ke tabel *Delta*. Tabel *dasar* adalah sumber utama kebenaran untuk negara sedangkan tabel *Delta* adalah jurnal Anda. *Jika Anda tidak meneruskan`lastSync: AWSTimestamp`, `syncPosts` kueri berjalan terhadap tabel *Base* dan menghidrasi cache serta berjalan pada waktu berkala sebagai *proses penangkapan global* untuk kasus tepi saat klien offline lebih lama dari waktu TTL yang dikonfigurasi di tabel Delta.* Jika Anda meneruskan`lastSync: AWSTimestamp`, `syncPosts` kueri berjalan terhadap tabel *Delta* Anda dan digunakan oleh klien untuk mengambil peristiwa yang diubah sejak terakhir offline. Amplify klien secara otomatis meneruskan `lastSync: AWSTimestamp` nilai, dan bertahan ke disk dengan tepat.

Bidang *\$1deleted* pada *Post* digunakan untuk operasi **DELETE**. Saat klien offline dan catatan dihapus dari tabel *Dasar*, atribut ini memberi tahu klien yang melakukan sinkronisasi untuk mengusir item dari cache lokal mereka. Dalam kasus di mana klien offline untuk jangka waktu yang lebih lama dan item telah dihapus sebelum klien dapat mengambil nilai ini dengan kueri Delta Sync, peristiwa pengejaran global dalam kueri dasar (dapat dikonfigurasi di klien) berjalan dan menghapus item dari cache. Bidang ini ditandai opsional karena hanya mengembalikan nilai saat menjalankan kueri sinkronisasi yang telah menghapus item yang ada.

## Mutasi
<a name="mutations"></a>

Untuk semua mutasi, AWS AppSync lakukan Create/Update/Delete operasi standar di tabel *Base* dan juga mencatat perubahan dalam tabel *Delta* secara otomatis. Anda dapat mengurangi atau memperpanjang waktu untuk menyimpan catatan dengan memodifikasi `DeltaSyncTableTTL` nilai pada sumber data. Untuk organisasi dengan kecepatan data yang tinggi, mungkin masuk akal untuk membuat ini singkat. Atau, jika klien Anda offline untuk jangka waktu yang lebih lama, mungkin bijaksana untuk menyimpannya lebih lama.

## Pertanyaan Sinkronisasi
<a name="sync-queries"></a>

*Kueri dasar* adalah operasi DynamoDB Sync tanpa `lastSync` nilai yang ditentukan. Bagi banyak organisasi, ini berfungsi karena kueri dasar hanya berjalan pada saat startup dan secara berkala setelahnya.

*Kueri delta* adalah operasi DynamoDB Sync dengan nilai yang ditentukan. `lastSync` *Kueri delta* dijalankan setiap kali klien kembali online dari status offline (selama waktu periodik kueri dasar belum dipicu untuk dijalankan). Klien secara otomatis melacak terakhir kali mereka berhasil menjalankan kueri untuk menyinkronkan data.

Ketika kueri delta dijalankan, resolver kueri menggunakan `ds_pk` dan `ds_sk` untuk melakukan kueri hanya untuk catatan yang telah berubah sejak terakhir kali klien melakukan sinkronisasi. Klien menyimpan respons GraphQL yang sesuai.

Untuk informasi selengkapnya tentang menjalankan Kueri Sinkronisasi, lihat dokumentasi [Operasi Sinkronisasi](aws-appsync-conflict-detection-and-sync-sync-operations.md).

## Contoh
<a name="example"></a>

Mari kita mulai dulu dengan memanggil `createPost` mutasi untuk membuat item:

```
mutation create {
  createPost(input: {author: "Nadia", title: "My First Post", content: "Hello World"}) {
    id
    author
    title
    content
    _version
    _lastChangedAt
    _deleted
  }
}
```

Nilai pengembalian mutasi ini akan terlihat sebagai berikut:

```
{
  "data": {
    "createPost": {
      "id": "81d36bbb-1579-4efe-92b8-2e3f679f628b",
      "author": "Nadia",
      "title": "My First Post",
      "content": "Hello World",
      "_version": 1,
      "_lastChangedAt": 1574469356331,
      "_deleted": null
    }
  }
}
```

Jika Anda memeriksa isi tabel *Base*, Anda akan melihat catatan yang terlihat seperti:

```
{
  "_lastChangedAt": {
    "N": "1574469356331"
  },
  "_version": {
    "N": "1"
  },
  "author": {
    "S": "Nadia"
  },
  "content": {
    "S": "Hello World"
  },
  "id": {
    "S": "81d36bbb-1579-4efe-92b8-2e3f679f628b"
  },
  "title": {
    "S": "My First Post"
  }
}
```

Jika Anda memeriksa isi tabel *Delta*, Anda akan melihat catatan yang terlihat seperti:

```
{
  "_lastChangedAt": {
    "N": "1574469356331"
  },
  "_ttl": {
    "N": "1574472956"
  },
  "_version": {
    "N": "1"
  },
  "author": {
    "S": "Nadia"
  },
  "content": {
    "S": "Hello World"
  },
  "ds_pk": {
    "S": "AppSync-delta-sync-post:2019-11-23"
  },
  "ds_sk": {
    "S": "00:35:56.331:81d36bbb-1579-4efe-92b8-2e3f679f628b:1"
  },
  "id": {
    "S": "81d36bbb-1579-4efe-92b8-2e3f679f628b"
  },
  "title": {
    "S": "My First Post"
  }
}
```

Sekarang kita dapat mensimulasikan kueri *Base* yang akan dijalankan klien untuk menghidrasi penyimpanan data lokalnya menggunakan `syncPosts` kueri seperti:

```
query baseQuery {
  syncPosts(limit: 100, lastSync: null, nextToken: null) {
    items {
      id
      author
      title
      content
      _version
      _lastChangedAt
    }
    startedAt
    nextToken
  }
}
```

Nilai kembali query *Base* ini akan terlihat sebagai berikut:

```
{
  "data": {
    "syncPosts": {
      "items": [
        {
          "id": "81d36bbb-1579-4efe-92b8-2e3f679f628b",
          "author": "Nadia",
          "title": "My First Post",
          "content": "Hello World",
          "_version": 1,
          "_lastChangedAt": 1574469356331
        }
      ],
      "startedAt": 1574469602238,
      "nextToken": null
    }
  }
}
```

Kita akan menyimpan `startedAt` nilainya nanti untuk mensimulasikan kueri *Delta*, tapi pertama-tama kita perlu membuat perubahan pada tabel kita. Mari gunakan `updatePost` mutasi untuk memodifikasi Posting kami yang ada:

```
mutation updatePost {
  updatePost(input: {id: "81d36bbb-1579-4efe-92b8-2e3f679f628b", _version: 1, title: "Actually this is my Second Post"}) {
    id
    author
    title
    content
    _version
    _lastChangedAt
    _deleted
  }
}
```

Nilai pengembalian mutasi ini akan terlihat sebagai berikut:

```
{
  "data": {
    "updatePost": {
      "id": "81d36bbb-1579-4efe-92b8-2e3f679f628b",
      "author": "Nadia",
      "title": "Actually this is my Second Post",
      "content": "Hello World",
      "_version": 2,
      "_lastChangedAt": 1574469851417,
      "_deleted": null
    }
  }
}
```

Jika Anda memeriksa isi tabel *Base* sekarang, Anda akan melihat item yang diperbarui:

```
{
  "_lastChangedAt": {
    "N": "1574469851417"
  },
  "_version": {
    "N": "2"
  },
  "author": {
    "S": "Nadia"
  },
  "content": {
    "S": "Hello World"
  },
  "id": {
    "S": "81d36bbb-1579-4efe-92b8-2e3f679f628b"
  },
  "title": {
    "S": "Actually this is my Second Post"
  }
}
```

Jika Anda memeriksa isi tabel *Delta* sekarang, Anda akan melihat dua catatan:

1. Catatan saat item dibuat

1. Catatan kapan item diperbarui.

Item baru akan terlihat seperti:

```
{
  "_lastChangedAt": {
    "N": "1574469851417"
  },
  "_ttl": {
    "N": "1574473451"
  },
  "_version": {
    "N": "2"
  },
  "author": {
    "S": "Nadia"
  },
  "content": {
    "S": "Hello World"
  },
  "ds_pk": {
    "S": "AppSync-delta-sync-post:2019-11-23"
  },
  "ds_sk": {
    "S": "00:44:11.417:81d36bbb-1579-4efe-92b8-2e3f679f628b:2"
  },
  "id": {
    "S": "81d36bbb-1579-4efe-92b8-2e3f679f628b"
  },
  "title": {
    "S": "Actually this is my Second Post"
  }
}
```

Sekarang kita dapat mensimulasikan kueri *Delta* untuk mengambil modifikasi yang terjadi ketika klien sedang offline. Kami akan menggunakan `startedAt` nilai yang dikembalikan dari kueri *Base* kami untuk membuat permintaan:

```
query delta {
  syncPosts(limit: 100, lastSync: 1574469602238, nextToken: null) {
    items {
      id
      author
      title
      content
      _version
    }
    startedAt
    nextToken
  }
}
```

Nilai pengembalian kueri *Delta* ini akan terlihat sebagai berikut:

```
{
  "data": {
    "syncPosts": {
      "items": [
        {
          "id": "81d36bbb-1579-4efe-92b8-2e3f679f628b",
          "author": "Nadia",
          "title": "Actually this is my Second Post",
          "content": "Hello World",
          "_version": 2
        }
      ],
      "startedAt": 1574470400808,
      "nextToken": null
    }
  }
}
```