

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 使用 設計 GraphQL APIs AWS AppSync
<a name="designing-a-graphql-api"></a>

AWS AppSync 可讓您使用主控台體驗建立 GraphQL APIs。您在[啟動範例結構描述](https://docs.aws.amazon.com/appsync/latest/devguide/quickstart.html)區段中一窺這一點。不過，該指南並未顯示您可以利用的完整選項和組態目錄 AWS AppSync。

當您選擇在主控台中建立 GraphQL API 時，有幾個選項可供探索。如果您遵循我們的[啟動範例結構描述](https://docs.aws.amazon.com/appsync/latest/devguide/quickstart.html)指南，我們會示範如何從預先定義的模型建立 API。在下列各節中，我們將引導您完成在其中建立 GraphQL APIs的其餘選項和組態 AWS AppSync。

在本節中，您將檢閱下列概念：

1. [Blank APIs or imports](blank-import-api.md#aws-appsync-blank-import-api)：本指南將執行建立 GraphQL API 的整個建立程序。您將了解如何從沒有模型的空白範本建立 GraphQL、設定結構描述的資料來源，以及將第一個解析程式新增至 欄位。

1. [Real-time data](aws-appsync-real-time-data.md#aws-appsync-real-time-data-anchor)：本指南將向您展示使用 WebSocket 引擎建立 API AWS AppSync的潛在選項。

1. [Merged APIs](merged-api.md#aws-appsync-merged-api)：本指南將示範如何透過關聯和合併來自多個現有 GraphQL APIs 的資料來建立新的 GraphQL APIs。

1. [使用 RDS 自我檢查建置 GraphQL APIs](rds-introspection.md)：本指南將說明如何使用資料 API 整合 Amazon RDS 資料表。

# 建構 GraphQL API （空白或匯入APIs)
<a name="blank-import-api"></a>

從空白範本建立 GraphQL API 之前，檢閱 GraphQL 的相關概念會有幫助。GraphQL API 有三個基本元件：

1. **結構描述**是包含資料形狀和定義的檔案。當用戶端向 GraphQL 服務提出請求時，傳回的資料將遵循結構描述的規格。如需詳細資訊，請參閱[GraphQL 結構描述](schema-components.md#aws-appsync-schema-components)。

1. **資料來源**會連接到您的結構描述。提出請求時，這是擷取和修改資料的位置。如需詳細資訊，請參閱[資料來源](data-source-components.md#aws-appsync-data-source-components)。

1. **解析程式**位於結構描述和資料來源之間。提出請求時，解析程式會對來源的資料執行 操作，然後傳回結果做為回應。如需詳細資訊，請參閱[解析程式](resolver-components.md#aws-appsync-resolver-components)。

![\[GraphQL API architecture showing schema, resolvers, and data sources connected via AppSync.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/appsync-architecture-graphql-api.png)


AWS AppSync 可讓您建立、編輯和存放結構描述和解析程式的程式碼，以管理您的 APIs。您的資料來源來自外部儲存庫，例如資料庫、DynamoDB 資料表和 Lambda 函數。如果您使用 AWS 服務來存放資料，或打算這麼做， 會在將資料從 AWS 您的帳戶與 GraphQL APIs 建立關聯時 AWS AppSync 提供近乎無縫的體驗。

在下一節中，您將了解如何使用 AWS AppSync 服務建立每個元件。

**Topics**
+ [設計 GraphQL 結構描述](designing-your-schema.md)
+ [連接資料來源](attaching-a-data-source.md)
+ [設定 AWS AppSync 解析程式](resolver-config-overview.md)
+ [搭配 CDK APIs](using-your-api.md)

# 設計 GraphQL 結構描述
<a name="designing-your-schema"></a>

GraphQL 結構描述是任何 GraphQL 伺服器實作的基礎。每個 GraphQL API 都由**單一**結構描述定義，其中包含描述請求資料如何填入的類型和欄位。流經 API 的資料和執行的操作必須針對結構描述進行驗證。

一般而言，[GraphQL 類型系統會](https://graphql.org/learn/schema/#type-system)描述 GraphQL 伺服器的功能，並用來判斷查詢是否有效。伺服器類型系統通常稱為該伺服器的結構描述，可包含不同的物件類型、純量類型、輸入類型等。GraphQL 是宣告式和強式類型，這表示類型將在執行時間妥善定義，並且只會傳回指定的類型。

AWS AppSync 可讓您定義和設定 GraphQL 結構描述。下一節說明如何使用 AWS AppSync的服務從頭開始建立 GraphQL 結構描述。

## 建構 GraphQL 結構描述
<a name="schema-structure"></a>

**提示**  
建議您先檢閱[結構描述](https://docs.aws.amazon.com//appsync/latest/devguide/schema-components.html)區段再繼續。

GraphQL 是實作 API 服務的強大工具。根據 [GraphQL 的網站](https://graphql.org/)，GraphQL 如下：

「*GraphQL 是 APIs的查詢語言，也是使用現有資料完成這些查詢的執行時間。GraphQL 提供 API 中資料的完整且易於理解的描述，讓用戶端能夠確切地詢問他們需要什麼，什麼都不做，讓隨著時間發展 APIs 變得更容易，並啟用強大的開發人員工具。*」

本節涵蓋 GraphQL 實作的第一部分：結構描述。使用上述引號，結構描述扮演「提供 API 中資料的完整且可理解描述」的角色。換句話說，GraphQL 結構描述是服務資料、操作及其之間關係的文字表示。結構描述會被視為 GraphQL 服務實作的主要進入點。令人意外的是，這通常是您在專案中做的第一件事之一。建議您先檢閱[結構描述](https://docs.aws.amazon.com//appsync/latest/devguide/schema-components.html)區段再繼續。

若要引用[結構描述](https://docs.aws.amazon.com//appsync/latest/devguide/schema-components.html)區段，GraphQL 結構描述會以*結構描述定義語言* (SDL) 撰寫。SDL 由具有已建立結構的類型和欄位組成：
+ **類型**：類型是 GraphQL 如何定義資料的形狀和行為。GraphQL 支援多種類型，將在本節稍後說明。結構描述中定義的每個類型都會包含自己的範圍。在範圍內，一個或多個欄位可以包含 GraphQL 服務中使用的值或邏輯。類型會填入許多不同的角色，最常見的是物件或純量 （基本值類型）。
+ **欄位**：欄位存在於 類型的範圍內，並保留從 GraphQL 服務請求的值。這些與其他程式設計語言的變數非常相似。您在欄位中定義的資料形狀將決定資料在請求/回應操作中的結構。這可讓開發人員預測傳回的內容，而不知道服務的後端如何實作。

最簡單的結構描述將包含三種不同的資料類別：

1. **結構描述根**目錄：根目錄定義結構描述的進入點。它指向將對資料執行一些操作的欄位，例如新增、刪除或修改某個項目。

1. **類型**：這些是用來代表資料形狀的基本類型。您幾乎可以將這些視為物件或具有已定義特性之物件的抽象表示法。例如，您可以製作代表資料庫中人員的`Person`物件。每個人的特性都會`Person`在 中定義為 欄位。它們可以是人員的名稱、年齡、工作、地址等。

1. **特殊物件類型**：這些是定義結構描述中操作行為的類型。每個特殊物件類型每個結構描述定義一次。它們會先放置在結構描述根目錄，然後在結構描述內文中定義。特殊物件類型中的每個欄位都會定義您的解析程式要實作的單一操作。

假設您正在建立可存放作者和他們所撰寫書籍的服務，以將其納入考量。每個作者都有一個名稱和他們撰寫的書籍陣列。每本書都有一個名稱和相關聯的作者清單。我們也希望能夠新增或擷取書籍和作者。此關係的簡單 UML 表示方式可能如下所示：

![\[UML diagram showing Author and Book classes with attributes and methods, linked by association.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/GraphQL-UML-1.png)


在 GraphQL 中，實體`Author`和 `Book`代表結構描述中的兩種不同的物件類型：

```
type Author {
}

type Book {
}
```

`Author` 包含 `authorName`和 `Books`，而 `Book`包含 `bookName`和 `Authors`。這些可以表示為您類型範圍內的欄位：

```
type Author {
  authorName: String
  Books: [Book]
}

type Book {
  bookName: String
  Authors: [Author]
}
```

如您所見，類型表示法非常接近圖表。不過，這些方法會變得較棘手。這些將放置在幾個特殊物件類型之一做為欄位。它們的特殊物件分類取決於其行為。GraphQL 包含三種基本的特殊物件類型：查詢、變動和訂閱。如需詳細資訊，請參閱[特殊物件](https://docs.aws.amazon.com//appsync/latest/devguide/graphql-types.html#special-object-components)。

由於 `getAuthor`和 `getBook` 都請求資料，因此它們將放置在`Query`特殊物件類型中：

```
type Author {
  authorName: String
  Books: [Book]
}

type Book {
  bookName: String
  Authors: [Author]
}

type Query {
  getAuthor(authorName: String): Author
  getBook(bookName: String): Book
}
```

操作會連結至查詢，而查詢本身會連結至結構描述。新增結構描述根將定義特殊物件類型 (`Query`在此案例中為 ) 做為其中一個進入點。這可以使用 `schema`關鍵字來完成：

```
schema {
  query: Query
}

type Author {
  authorName: String
  Books: [Book]
}

type Book {
  bookName: String
  Authors: [Author]
}

type Query {
  getAuthor(authorName: String): Author
  getBook(bookName: String): Book
}
```

查看最後兩種方法，`addAuthor``addBook`並將資料新增至資料庫，因此它們將以`Mutation`特殊物件類型定義。不過，從[類型](https://docs.aws.amazon.com/appsync/latest/devguide/graphql-types.html#input-components)頁面，我們也知道不允許直接參考物件的輸入，因為它們是嚴格輸出類型。在這種情況下，我們無法使用 `Author`或 `Book`，因此我們需要使用相同的欄位建立輸入類型。在此範例中，我們新增了 `AuthorInput`和 `BookInput`，兩者都接受各自類型的相同欄位。然後，我們使用輸入做為參數來建立變動：

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

type Author {
  authorName: String
  Books: [Book]
}

input AuthorInput {
  authorName: String
  Books: [BookInput]
}

type Book {
  bookName: String
  Authors: [Author]
}

input BookInput {
  bookName: String
  Authors: [AuthorInput]
}

type Query {
  getAuthor(authorName: String): Author
  getBook(bookName: String): Book
}

type Mutation {
  addAuthor(input: [BookInput]): Author
  addBook(input: [AuthorInput]): Book
}
```

讓我們檢閱剛執行的操作：

1. 我們已使用 `Book`和 `Author`類型建立結構描述，以代表我們的實體。

1. 我們新增了包含實體特性的欄位。

1. 我們新增了查詢，以從資料庫擷取此資訊。

1. 我們新增了變動來操作資料庫中的資料。

1. 我們新增輸入類型來取代變動中的物件參數，以符合 GraphQL 的規則。

1. 我們已將查詢和變動新增至根結構描述，以便 GraphQL 實作了解根類型位置。

如您所見，建立結構描述的程序通常需要資料建模 （特別是資料庫建模） 的許多概念。您可以將結構描述視為符合來源資料的形狀。它也可以做為解析程式將實作的模型。在下列各節中，您將了解如何使用各種 AWS支援的工具和服務建立結構描述。

**注意**  
以下各節中的範例並非要在真正的應用程式中執行。它們只用來展示命令，因此您可以建置自己的應用程式。

## 建立結構描述
<a name="creating-schema"></a>

您的結構描述將位於名為 `schema.graphql`. AWS AppSync 的檔案中，允許使用者使用各種方法為其 GraphQL APIs 建立新的結構描述。在此範例中，我們將建立空白 API 以及空白結構描述。

------
#### [ Console ]

1. 登入 AWS 管理主控台 並開啟 [AppSync 主控台](https://console.aws.amazon.com/appsync/)。

   1. 在**儀表板**上，選擇 **Create API (建立 API)**。

   1. 在 **API 選項**下，選擇 **GraphQL APIs**、**從頭開始設計**，然後選擇**下一步**。

      1. 針對 **API 名稱**，請將預先填入的名稱變更為應用程式所需的名稱。

      1. 如需**聯絡詳細資訊**，您可以輸入聯絡點來識別 API 的管理員。此為選用欄位。

      1. 在**私有 API 組態**下，您可以啟用私有 API 功能。私有 API 只能從設定的 VPC 端點 (VPCE) 存取。如需詳細資訊，請參閱[私有 APIs](https://docs.aws.amazon.com/appsync/latest/devguide/using-private-apis.html)。

         不建議在此範例中啟用此功能。檢閱您的輸入後，請選擇**下一步**。

   1. 在**建立 GraphQL 類型**下，您可以選擇建立 DynamoDB 資料表以用作資料來源，或略過此項目並在稍後執行。

      在此範例中，選擇**稍後建立 GraphQL 資源**。我們將在單獨的區段中建立資源。

   1. 檢閱您的輸入，然後選擇**建立 API**。

1. 您將位於特定 API 的儀表板中。您可以指出 ，因為 API 的名稱會位於儀表板頂端。如果不是這種情況，您可以在 **Sidebar** 中選取 **APIs**，然後在 API **儀表板中選擇您的 APIs**。

   1. 在 API 名稱下方的 **Sidebar** 中，選擇**結構描述**。

1. 在**結構描述編輯器**中，您可以設定 `schema.graphql` 檔案。它可以是空的或填滿從模型產生的類型。在右側，您有**將解析程式**連接至結構描述欄位的解析程式區段。我們不會查看本節中的解析程式。

------
#### [ CLI ]

**注意**  
使用 CLI 時，請確定您擁有在 服務中存取和建立資源的正確許可。您可能想要為需要存取服務的非管理員使用者設定[最低權限](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege)政策。如需 AWS AppSync 政策的詳細資訊，請參閱 [的 Identity and Access Management AWS AppSync](https://docs.aws.amazon.com//appsync/latest/devguide/security-iam.html)。  
此外，如果您尚未閱讀主控台版本，建議您先閱讀。

1. 如果您尚未這麼做，請 AWS [安裝](https://docs.aws.amazon.com//cli/latest/userguide/cli-chap-getting-started.html) CLI，然後新增您的[組態](https://docs.aws.amazon.com//cli/latest/userguide/cli-configure-quickstart.html)。

1. 執行 [https://docs.aws.amazon.com/cli/latest/reference/appsync/create-graphql-api.html](https://docs.aws.amazon.com/cli/latest/reference/appsync/create-graphql-api.html)命令來建立 GraphQL API 物件。

   您需要為此特定命令輸入兩個參數：

   1. 您 API `name`的 。

   1. `authentication-type`，或用於存取 API 的登入資料類型 (IAM、OIDC 等）。
**注意**  
必須設定其他參數，例如 `Region` ，但通常會預設為您的 CLI 組態值。

   範例命令可能如下所示：

   ```
   aws appsync create-graphql-api --name testAPI123 --authentication-type API_KEY
   ```

   輸出會在 CLI 中傳回。範例如下：

   ```
   {
       "graphqlApi": {
           "xrayEnabled": false,
           "name": "testAPI123",
           "authenticationType": "API_KEY",
           "tags": {},
           "apiId": "abcdefghijklmnopqrstuvwxyz",
           "uris": {
               "GRAPHQL": "https://zyxwvutsrqponmlkjihgfedcba.appsync-api.us-west-2.amazonaws.com/graphql",
               "REALTIME": "wss://zyxwvutsrqponmlkjihgfedcba.appsync-realtime-api.us-west-2.amazonaws.com/graphql"
           },
           "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz"
       }
   }
   ```

1. 
**注意**  
這是選用的命令，採用現有的結構描述，並使用 base-64 Blob 將其上傳至 AWS AppSync 服務。基於此範例，我們不會使用此命令。

   執行 [https://docs.aws.amazon.com/cli/latest/reference/appsync/start-schema-creation.html](https://docs.aws.amazon.com/cli/latest/reference/appsync/start-schema-creation.html) 命令。

   您需要為此特定命令輸入兩個參數：

   1. 上一個步驟`api-id`的 。

   1. 結構描述`definition`是 base-64 編碼的二進位 Blob。

   範例命令可能如下所示：

   ```
    aws appsync start-schema-creation --api-id abcdefghijklmnopqrstuvwxyz --definition "aa1111aa-123b-2bb2-c321-12hgg76cc33v"
   ```

   將傳回輸出：

   ```
   {
       "status": "PROCESSING"
   }
   ```

   此命令不會在處理後傳回最終輸出。您必須使用單獨的命令 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/get-schema-creation-status.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/get-schema-creation-status.html)來查看結果。請注意，這兩個命令是非同步的，因此即使結構描述仍在建立中，您也可以檢查輸出狀態。

------
#### [ CDK ]

**提示**  
在使用 CDK 之前，建議您檢閱 CDK 的[官方文件](https://docs.aws.amazon.com/cdk/v2/guide/home.html)以及 CDK AWS AppSync參考。 [https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html)  
下列步驟只會顯示用來新增特定資源之程式碼片段的一般範例。這**並非**您生產程式碼中的工作解決方案。我們也假設您已經有運作中的應用程式。

1. CDK 的起點略有不同。理想情況下，應該已建立您的`schema.graphql`檔案。您只需要使用副檔名建立新的`.graphql`檔案。這可以是空白檔案。

1. 一般而言，您可能需要將匯入指令新增至您正在使用的服務。例如，它可能會遵循以下表單：

   ```
   import * as x from 'x'; # import wildcard as the 'x' keyword from 'x-service'
   import {a, b, ...} from 'c'; # import {specific constructs} from 'c-service'
   ```

   若要新增 GraphQL API，您的堆疊檔案需要匯入 AWS AppSync 服務：

   ```
   import * as appsync from 'aws-cdk-lib/aws-appsync';
   ```
**注意**  
這表示我們正在`appsync`關鍵字下匯入整個服務。若要在您的應用程式中使用此功能，您的 AWS AppSync 建構會使用 格式 `appsync.construct_name`。例如，如果我們想要製作 GraphQL API，我們會說 `new appsync.GraphqlApi(args_go_here)`。下列步驟說明了這一點。

1. 最基本的 GraphQL API 將包含 API `name` 和 `schema` 路徑的 。

   ```
   const add_api = new appsync.GraphqlApi(this, 'API_ID', {
     name: 'name_of_API_in_console',
     schema: appsync.SchemaFile.fromAsset(path.join(__dirname, 'schema_name.graphql')),
   });
   ```
**注意**  
讓我們檢閱此程式碼片段的功能。在 範圍內`api`，我們呼叫 來建立新的 GraphQL API`appsync.GraphqlApi(scope: Construct, id: string, props: GraphqlApiProps)`。範圍為 `this`，是指目前的物件。ID 是 *API\$1ID*，其將在建立 CloudFormation 時做為 GraphQL API 的資源名稱。`GraphqlApiProps` 包含 GraphQL API `name`的 和 `schema`。`schema` 將透過搜尋`.graphql`檔案的絕對路徑 (`SchemaFile.fromAsset`) (*schema\$1name.graphql*) 來產生結構描述 (`__dirname`)。在實際案例中，您的結構描述檔案可能位於 CDK 應用程式內。  
若要使用對 GraphQL API 所做的變更，您必須重新部署應用程式。

------

## 將類型新增至結構描述
<a name="adding-schema-types"></a>

現在您已新增結構描述，您可以開始同時新增輸入和輸出類型。請注意，此處的類型不應用於真實程式碼；它們只是協助您了解程序的範例。

首先，我們會建立物件類型。在真實程式碼中，您不需要從這些類型開始。只要您遵循 GraphQL 的規則和語法，您可以隨時進行您想要的類型。

**注意**  
接下來的幾個區段將使用**結構描述編輯器**，因此請保持開啟狀態。

------
#### [ Console ]
+ 您可以使用 `type`關鍵字以及 類型的名稱來建立物件類型：

  ```
  type Type_Name_Goes_Here {}
  ```

  在類型範圍內，您可以新增代表物件特性的欄位：

  ```
  type Type_Name_Goes_Here {
    # Add fields here
  }
  ```

  範例如下：

  ```
  type Obj_Type_1 {
    id: ID!
    title: String
    date: AWSDateTime
  }
  ```
**注意**  
在此步驟中，我們新增了一個一般物件類型，其中包含存放為 的必要`id`欄位`ID`、存放為 `title`的欄位`String`，以及存放為 `date`的欄位`AWSDateTime`。若要查看類型和欄位清單及其用途，請參閱[結構描述](https://docs.aws.amazon.com//appsync/latest/devguide/schema-components.html)。若要查看純量清單及其用途，請參閱[類型參考](https://docs.aws.amazon.com/appsync/latest/devguide/type-reference.html)。

------
#### [ CLI ]

**注意**  
如果您尚未閱讀主控台版本，建議您先閱讀該版本。
+ 您可以執行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html)命令來建立物件類型。

  您需要為此特定命令輸入幾個參數：

  1. 您 API `api-id`的 。

  1. `definition`或 類型的內容。在主控台範例中，這是：

     ```
     type Obj_Type_1 {
       id: ID!
       title: String
       date: AWSDateTime
     }
     ```

  1. 您輸入的 `format` 。在此範例中，我們使用 `SDL`。

  範例命令可能如下所示：

  ```
  aws appsync create-type --api-id abcdefghijklmnopqrstuvwxyz --definition "type Obj_Type_1{id: ID! title: String date: AWSDateTime}" --format SDL
  ```

  輸出會在 CLI 中傳回。範例如下：

  ```
  {
      "type": {
          "definition": "type Obj_Type_1{id: ID! title: String date: AWSDateTime}",
          "name": "Obj_Type_1",
          "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Obj_Type_1",
          "format": "SDL"
      }
  }
  ```
**注意**  
在此步驟中，我們新增了一個一般物件類型，其中包含存放為 的必要`id`欄位`ID`、存放為 `title`的欄位`String`，以及存放為 `date`的欄位`AWSDateTime`。若要查看類型和欄位清單及其用途，請參閱[結構描述](https://docs.aws.amazon.com//appsync/latest/devguide/schema-components.html)。若要查看純量清單及其用途，請參閱[類型參考](https://docs.aws.amazon.com/appsync/latest/devguide/type-reference.html)。  
進一步說明，您可能已意識到輸入定義直接適用於較小的類型，但無法用於新增較大的或多種類型。您可以選擇在`.graphql`檔案中新增所有項目，然後將其[做為輸入](https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-parameters-file.html)傳遞。

------
#### [ CDK ]

**提示**  
在使用 CDK 之前，建議您檢閱 CDK 的[官方文件](https://docs.aws.amazon.com/cdk/v2/guide/home.html)以及 CDK AWS AppSync參考。 [https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html)  
下列步驟只會顯示用來新增特定資源之程式碼片段的一般範例。**這不是**生產程式碼中的工作解決方案。我們也假設您已經有運作中的應用程式。

若要新增類型，您需要將其新增至您的 `.graphql` 檔案。例如，主控台範例為：

```
type Obj_Type_1 {
  id: ID!
  title: String
  date: AWSDateTime
}
```

您可以將類型直接新增至結構描述，就像任何其他檔案一樣。

**注意**  
若要使用對 GraphQL API 所做的變更，您必須重新部署應用程式。

------

[物件類型](https://graphql.org/learn/schema/#object-types-and-fields)具有[純量類型的](https://graphql.org/learn/schema/#scalar-types)欄位，例如字串和整數。 AWS AppSync 也可讓您除了基本 GraphQL 純量`AWSDateTime`之外，使用 等增強純量類型。此外，結尾為驚嘆號的任何欄位都是必要的。

特別是`ID`純量類型是唯一識別符，可以是 `String`或 `Int`。您可以在解析程式程式碼中控制這些項目以進行自動指派。

特殊物件類型之間有相似之處，例如 `Query`和上述範例的「一般」物件類型，因為它們都使用`type`關鍵字並被視為物件。不過，對於特殊物件類型 (`Query`、 和 `Subscription`)`Mutation`，其行為非常不同，因為它們會公開為 API 的進入點。它們也與塑造操作而非資料有關。如需詳細資訊，請參閱[查詢和變動類型](https://graphql.org/learn/schema/#the-query-and-mutation-types)。

在特殊物件類型的主題上，下一個步驟可能是新增一或多個物件，以對形狀資料執行操作。在實際案例中，每個 GraphQL 結構描述至少必須具有請求資料的根查詢類型。您可以將查詢視為 GraphQL 伺服器的其中一個進入點 （或端點）。讓我們新增查詢做為範例。

------
#### [ Console ]
+ 若要建立查詢，您可以直接將其新增至結構描述檔案，就像任何其他類型一樣。查詢需要`Query`類型和根目錄中的項目，如下所示：

  ```
  schema {
    query: Name_of_Query
  }
  
  type Name_of_Query {
    # Add field operation here
  }
  ```

  請注意，`Query`在大多數情況下，生產環境中的 *Name\$1of\$1Query* 只會被呼叫。我們建議將其保持在此值。在查詢類型中，您可以新增欄位。每個欄位都會在請求中執行 操作。因此，如果不是全部，則大多數這些欄位都會連接到解析程式。不過，在本節中，我們並不關心這一點。關於欄位操作的格式，可能如下所示：

  ```
  Name_of_Query(params): Return_Type # version with params
  Name_of_Query: Return_Type # version without params
  ```

  範例如下：

  ```
  schema {
    query: Query
  }
  
  type Query {
    getObj: [Obj_Type_1]
  }
  
  type Obj_Type_1 {
    id: ID!
    title: String
    date: AWSDateTime
  }
  ```
**注意**  
在此步驟中，我們新增了 `Query`類型，並將其定義在我們的`schema`根目錄中。我們的`Query`類型定義了傳回`Obj_Type_1`物件清單`getObj`的欄位。請注意， `Obj_Type_1`是上一個步驟的物件。在生產程式碼中，您的欄位操作通常會使用 這類物件所塑造的資料`Obj_Type_1`。此外， 等欄位`getObj`通常會有解析程式來執行商業邏輯。這將在不同的章節中涵蓋。  
另請注意， 會在匯出期間 AWS AppSync 自動新增結構描述根目錄，因此在技術上您不需要將其直接新增至結構描述。我們的服務會自動處理重複的結構描述。我們將這裡新增為最佳實務。

------
#### [ CLI ]

**注意**  
如果您尚未閱讀主控台版本，建議您先閱讀該版本。

1. 執行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html)命令，以建立具有 `query`定義的`schema`根目錄。

   您需要為此特定命令輸入幾個參數：

   1. 您 API `api-id`的 。

   1. `definition`或 類型的內容。在主控台範例中，這是：

      ```
      schema {
        query: Query
      }
      ```

   1. 您輸入的 `format` 。在此範例中，我們使用 `SDL`。

   範例命令可能如下所示：

   ```
   aws appsync create-type --api-id abcdefghijklmnopqrstuvwxyz --definition "schema {query: Query}" --format SDL
   ```

   輸出會在 CLI 中傳回。範例如下：

   ```
   {
       "type": {
           "definition": "schema {query: Query}",
           "name": "schema",
           "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/schema",
           "format": "SDL"
       }
   }
   ```
**注意**  
請注意，如果您未在`create-type`命令中正確輸入內容，您可以執行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-type.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-type.html)命令來更新結構描述根目錄 （或結構描述中的任何類型）。在此範例中，我們將暫時變更結構描述根目錄以包含`subscription`定義。  
您需要為此特定命令輸入幾個參數：  
您 API `api-id`的 。
`type-name` 您 類型的 。在主控台範例中，這是 `schema`。
`definition`或 類型的內容。在主控台範例中，這是：  

      ```
      schema {
        query: Query
      }
      ```
新增 後的結構描述`subscription`如下所示：  

      ```
      schema {
        query: Query
        subscription: Subscription
      }
      ```
您輸入的 `format` 。在此範例中，我們使用 `SDL`。
範例命令可能如下所示：  

   ```
   aws appsync update-type --api-id abcdefghijklmnopqrstuvwxyz --type-name schema --definition "schema {query: Query subscription: Subscription}" --format SDL
   ```
輸出會在 CLI 中傳回。範例如下：  

   ```
   {
       "type": {
           "definition": "schema {query: Query subscription: Subscription}",
           "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/schema",
           "format": "SDL"
       }
   }
   ```
在此範例中，新增預先格式化的檔案仍然有效。

1. 執行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html)命令來建立 `Query` 類型。

   您需要為此特定命令輸入幾個參數：

   1. 您 API `api-id`的 。

   1. `definition`或 類型的內容。在主控台範例中，這是：

      ```
      type Query {
        getObj: [Obj_Type_1]
      }
      ```

   1. 您輸入的 `format` 。在此範例中，我們使用 `SDL`。

   範例命令可能如下所示：

   ```
   aws appsync create-type --api-id abcdefghijklmnopqrstuvwxyz --definition "type Query {getObj: [Obj_Type_1]}" --format SDL
   ```

   輸出會在 CLI 中傳回。範例如下：

   ```
   {
       "type": {
           "definition": "Query {getObj: [Obj_Type_1]}",
           "name": "Query",
           "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Query",
           "format": "SDL"
       }
   }
   ```
**注意**  
在此步驟中，我們新增了 `Query`類型，並將其定義在您的`schema`根目錄中。我們的`Query`類型定義了傳回`Obj_Type_1`物件清單`getObj`的欄位。  
在`schema`根碼 中`query: Query`， `query:`部分表示查詢已在您的結構描述中定義，而 `Query`部分表示實際的特殊物件名稱。

------
#### [ CDK ]

**提示**  
在使用 CDK 之前，我們建議您檢閱 CDK 的[官方文件](https://docs.aws.amazon.com/cdk/v2/guide/home.html)以及 CDK AWS AppSync參考。 [https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html)  
下列步驟只會顯示用來新增特定資源之程式碼片段的一般範例。這**並非**您生產程式碼中的工作解決方案。我們也假設您已經有運作中的應用程式。

您需要將查詢和結構描述根新增至 `.graphql` 檔案。我們的範例看起來像以下範例，但您會想要將其取代為實際的結構描述程式碼：

```
schema {
  query: Query
}

type Query {
  getObj: [Obj_Type_1]
}

type Obj_Type_1 {
  id: ID!
  title: String
  date: AWSDateTime
}
```

您可以將類型直接新增至結構描述，就像任何其他檔案一樣。

**注意**  
更新結構描述根目錄是選用的。我們將此範例新增為最佳實務。  
若要使用對 GraphQL API 所做的變更，您必須重新部署應用程式。

------

您現在已看到建立物件和特殊物件 （查詢） 的範例。您也已了解這些如何相互連結來描述資料和操作。您可以只具有資料描述和一或多個查詢的結構描述。不過，我們希望新增另一個操作，將資料新增至資料來源。我們會新增另一個名為 的特殊物件類型`Mutation`來修改資料。

------
#### [ Console ]
+ 變動將稱為 `Mutation`。如同 `Query`，內部的欄位操作`Mutation`將描述 操作，並將連接到解析程式。此外，請注意，我們需要在`schema`根中定義它，因為它是一種特殊的物件類型。以下是變動的範例：

  ```
  schema {
    mutation: Name_of_Mutation
  }
  
  type Name_of_Mutation {
    # Add field operation here
  }
  ```

  典型的變動會在根目錄中列出，例如查詢。變動是使用`type`關鍵字和名稱來定義。*Name\$1of\$1Mutation* 通常稱為 `Mutation`，因此我們建議您以這種方式保留它。每個欄位也會執行 操作。關於欄位操作的格式，可能如下所示：

  ```
  Name_of_Mutation(params): Return_Type # version with params
  Name_of_Mutation: Return_Type # version without params
  ```

  範例如下：

  ```
  schema {
    query: Query
    mutation: Mutation
  }
  
  type Obj_Type_1 {
    id: ID!
    title: String
    date: AWSDateTime
  }
  
  type Query {
    getObj: [Obj_Type_1]
  }
  
  type Mutation {
    addObj(id: ID!, title: String, date: AWSDateTime): Obj_Type_1
  }
  ```
**注意**  
在此步驟中，我們新增了具有 `addObj` 欄位的`Mutation`類型。讓我們總結此欄位的功能：  

  ```
  addObj(id: ID!, title: String, date: AWSDateTime): Obj_Type_1
  ```
`addObj` 正在使用 `Obj_Type_1` 物件來執行 操作。這是顯而易見的，因為欄位，但語法在`: Obj_Type_1`傳回類型中證明這一點。在 中`addObj`，它接受`Obj_Type_1`來自 物件的 `title`、 `id`和 `date` 欄位做為參數。如您所見，它看起來很像方法宣告。不過，我們尚未說明方法的行為。如前所述，結構描述只會用來定義資料和操作的內容，而不是它們的運作方式。當我們建立第一個解析程式時，實作實際的商業邏輯會稍後出現。  
完成結構描述後，您可以選擇將其匯出為 `schema.graphql` 檔案。在**結構描述編輯器**中，您可以選擇**匯出結構描述**，以支援的格式下載檔案。  
另請注意， 會在匯出期間 AWS AppSync 自動新增結構描述根目錄，因此在技術上您不需要將其直接新增至結構描述。我們的服務會自動處理重複的結構描述。我們將這裡新增為最佳實務。

------
#### [ CLI ]

**注意**  
如果您尚未閱讀主控台版本，建議您先閱讀該版本。

1. 執行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-type.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-type.html)命令來更新您的根結構描述。

   您需要為此特定命令輸入幾個參數：

   1. 您 API `api-id`的 。

   1. `type-name` 您 類型的 。在主控台範例中，這是 `schema`。

   1. `definition`或 類型的內容。在主控台範例中，這是：

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

   1. 您輸入的 `format` 。在此範例中，我們使用 `SDL`。

   範例命令可能如下所示：

   ```
   aws appsync update-type --api-id abcdefghijklmnopqrstuvwxyz --type-name schema --definition "schema {query: Query mutation: Mutation}" --format SDL
   ```

   輸出會在 CLI 中傳回。範例如下：

   ```
   {
       "type": {
           "definition": "schema {query: Query mutation: Mutation}",
           "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/schema",
           "format": "SDL"
       }
   }
   ```

1. 執行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-type.html)命令來建立 `Mutation` 類型。

   您需要為此特定命令輸入幾個參數：

   1. 您 API `api-id`的 。

   1. `definition`或 類型的內容。在主控台範例中，這是

      ```
      type Mutation {
        addObj(id: ID!, title: String, date: AWSDateTime): Obj_Type_1
      }
      ```

   1. 您輸入的 `format` 。在此範例中，我們使用 `SDL`。

   範例命令可能如下所示：

   ```
   aws appsync create-type --api-id abcdefghijklmnopqrstuvwxyz --definition "type Mutation {addObj(id: ID! title: String date: AWSDateTime): Obj_Type_1}" --format SDL
   ```

   輸出會在 CLI 中傳回。範例如下：

   ```
   {
       "type": {
           "definition": "type Mutation {addObj(id: ID! title: String date: AWSDateTime): Obj_Type_1}",
           "name": "Mutation",
           "arn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Mutation",
           "format": "SDL"
       }
   }
   ```

------
#### [ CDK ]

**提示**  
在使用 CDK 之前，我們建議您檢閱 CDK 的[官方文件](https://docs.aws.amazon.com/cdk/v2/guide/home.html)以及 CDK AWS AppSync參考。 [https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html)  
下列步驟只會顯示用來新增特定資源之程式碼片段的一般範例。這**並非**您生產程式碼中的工作解決方案。我們也假設您已經有運作中的應用程式。

您需要將查詢和結構描述根新增至 `.graphql` 檔案。我們的範例看起來像以下範例，但您會想要將其取代為實際的結構描述程式碼：

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

type Obj_Type_1 {
  id: ID!
  title: String
  date: AWSDateTime
}

type Query {
  getObj: [Obj_Type_1]
}

type Mutation {
  addObj(id: ID!, title: String, date: AWSDateTime): Obj_Type_1
}
```

**注意**  
更新結構描述根目錄是選用的。我們將此範例新增為最佳實務。  
若要使用對 GraphQL API 所做的變更，您必須重新部署應用程式。

------

## 選用考量 - 使用列舉做為狀態
<a name="optional-consideration-enums"></a>

此時，您知道如何建立基本結構描述。不過，您可以新增許多項目來增加結構描述的功能。在應用程式中發現的一個常見情況是使用列舉做為狀態。您可以使用列舉來強制在呼叫時選擇一組值中的特定值。這對您知道不會長時間發生劇烈變化的事物很有用。假設我們可以新增 enum，在回應中傳回狀態碼或字串。

例如，假設我們製作的社交媒體應用程式將使用者的文章資料存放在後端。我們的結構描述包含代表個別文章資料的`Post`類型：

```
type Post {
  id: ID!
  title: String
  date: AWSDateTime
  poststatus: PostStatus
}
```

我們的 `Post` 將包含一個唯一的 `id`、貼文 `title`和一個名為 `date`的列舉`PostStatus`，代表應用程式處理貼文時的狀態。對於我們的操作，我們將有一個查詢，會傳回所有文章資料：

```
type Query {
  getPosts: [Post]
}
```

我們也會有一個變動，將文章新增至資料來源：

```
type Mutation {
  addPost(id: ID!, title: String, date: AWSDateTime, poststatus: PostStatus): Post
}
```

查看我們的結構描述，`PostStatus`列舉可能有數種狀態。我們可能會希望名為 `success`（已成功處理文章）、 `pending` （正在處理文章） 和 `error`（無法處理文章） 的三個基本狀態。若要新增列舉，我們可以執行下列動作：

```
enum PostStatus {
  success
  pending
  error
}
```

完整的結構描述可能如下所示：

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

type Post {
  id: ID!
  title: String
  date: AWSDateTime
  poststatus: PostStatus
}

type Mutation {
  addPost(id: ID!, title: String, date: AWSDateTime, poststatus: PostStatus): Post
}

type Query {
  getPosts: [Post]
}

enum PostStatus {  
  success
  pending
  error
}
```

如果使用者`Post`在應用程式中新增 ，則會呼叫 `addPost`操作來處理該資料。當連接至 的解析程式`addPost`處理資料時，它會持續更新`poststatus`具有 操作狀態的 。查詢時， `Post`將包含資料的最終狀態。請記住，我們只會描述我們希望資料在結構描述中的運作方式。我們正在假設許多有關 （解析程式） 的實作，這會實作實際的商業邏輯來處理資料以滿足請求。

## 選用考量 - 訂閱
<a name="optional-consideration-subscriptions"></a>

訂閱 in AWS AppSync 被調用為對變動的回應。您可利用結構描述之中的 `Subscription` 類型及 `@aws_subscribe()` 指令進行設定，表示哪些變動用於叫用一項以上的訂閱。如需設定訂閱的詳細資訊，請參閱[即時資料](https://docs.aws.amazon.com/appsync/latest/devguide/aws-appsync-real-time-data.html)。

## 選用考量 - 關係和分頁
<a name="optional-consideration-relations-and-pagination"></a>

假設您在 DynamoDB 資料表中`Posts`存放了一百萬個資料，而且您想要傳回其中一些資料。不過，上述提供的範例查詢只會傳回所有文章。您不會想要在每次提出請求時擷取所有這些項目。反之，您會想要透過它們[進行分頁](https://graphql.org/learn/pagination/)。請對結構描述進行下列變更：
+ 在 `getPosts`欄位中，新增兩個輸入引數： `nextToken`（迭代器） 和 `limit`（迭代限制）。
+ 新增包含 `Posts`（擷取`Post`物件清單） 和 `nextToken`（迭代器） 欄位的新`PostIterator`類型。
+ 變更 ，`getPosts`使其傳回 `PostIterator` ，而不是`Post`物件清單。

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

type Post {
  id: ID!
  title: String
  date: AWSDateTime
  poststatus: PostStatus
}

type Mutation {
  addPost(id: ID!, title: String, date: AWSDateTime, poststatus: PostStatus): Post
}

type Query {
  getPosts(limit: Int, nextToken: String): PostIterator
}

enum PostStatus {
  success
  pending
  error
}

type PostIterator {
  posts: [Post]
  nextToken: String
}
```

`PostIterator` 類型可讓您傳回`Post`物件清單的一部分，以及`nextToken`用於取得下一個部分的 。在 中`PostIterator`，有一個項目清單 `Post`(`[Post]`) 以分頁字符 () 傳回`nextToken`。In AWS AppSync，這會透過解析程式連線至 Amazon DynamoDB，並自動產生為加密字符。這會將 `limit` 引數的值轉換成 `maxResults` 參數，並將 `nextToken` 引數轉換成 `exclusiveStartKey` 參數。如需 AWS AppSync 主控台中的範例和內建範本範例，請參閱[解析程式參考 (JavaScript)](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-js-version.html)。

# 連接資料來源 in AWS AppSync
<a name="attaching-a-data-source"></a>

資料來源是您 AWS 帳戶中 GraphQL APIs 可與之互動的資源。 AWS AppSync 支援多種資料來源 AWS Lambda，例如 Amazon DynamoDB、關聯式資料庫 (Amazon Aurora Serverless)、Amazon OpenSearch Service 和 HTTP 端點。An AWS AppSync API 可以設定為與多個資料來源互動，讓您能夠在單一位置彙總資料。 AWS AppSync 可以使用您帳戶中的現有 AWS 資源，或從結構描述定義代表您佈建 DynamoDB 資料表。

下一節將示範如何將資料來源連接至 GraphQL API。

## 資料來源的類型
<a name="data-source-types"></a>

現在您已在 AWS AppSync 主控台中建立結構描述，您可以將資料來源連接至該結構描述。當您最初建立 API 時，可以選擇在建立預先定義的結構描述期間佈建 Amazon DynamoDB 資料表。不過，我們不會在本節中涵蓋該選項。您可以在[啟動結構描述](https://docs.aws.amazon.com//appsync/latest/devguide/schema-launch-start.html)區段中看到此範例。

反之，我們將查看 AWS AppSync 支援的所有資料來源。為您的應用程式挑選正確的解決方案有許多因素。以下各節將為每個資料來源提供一些額外的內容。如需資料來源的一般資訊，請參閱[資料來源](https://docs.aws.amazon.com/appsync/latest/devguide/data-source-components.html)。

### Amazon DynamoDB
<a name="data-source-type-ddb"></a>

Amazon DynamoDB 是可擴展應用程式 AWS的主要儲存解決方案之一。DynamoDB 的核心元件是 **資料表**，只是資料集合。您通常會根據 `Book`或 等實體建立資料表`Author`。資料表項目資訊會儲存為**項目**，這些項目是每個項目唯一的欄位群組。完整項目代表資料庫中的資料列/記錄。例如，`Book`項目的項目可能包含 `title`和 `author`及其值。`title` 和 等個別欄位`author`稱為**屬性**，與關聯式資料庫中的資料欄值類似。

您可以猜測，資料表將用於存放應用程式的資料。 AWS AppSync 可讓您將 DynamoDB 資料表連接至 GraphQL API 以操作資料。從*前端 Web 和行動部落格*取得此[使用案例](https://aws.amazon.com/blogs/mobile/new-real-time-multi-group-app-with-aws-amplify-graphql-build-a-twitter-community-clone/)。此應用程式可讓使用者註冊社交媒體應用程式。使用者可以加入群組，並上傳廣播給其他訂閱該群組的使用者的文章。其應用程式會將使用者、文章和使用者群組資訊存放在 DynamoDB 中。GraphQL API （由 管理 AWS AppSync) 會與 DynamoDB 資料表連接。當使用者在系統進行將反映在前端的變更時，GraphQL API 會擷取這些變更並將其即時廣播給其他使用者。

### AWS Lambda
<a name="data-source-type-lam"></a>

Lambda 是一種事件驅動服務，可自動建置必要的資源，以執行程式碼作為事件的回應。Lambda 使用 **函數**，這些函數是包含程式碼、相依性和組態的群組陳述式，用於執行資源。函數會在偵測到**觸發**條件時自動執行，這是叫用函數的一組活動。觸發可以是發出 API 呼叫的應用程式、您帳戶中啟動資源 AWS 的服務等。觸發時， 函數會處理事件，這些**事件**是包含要修改之資料的 JSON 文件。

Lambda 非常適合執行程式碼，無需佈建資源即可執行。從*前端 Web 和行動部落格*取得此[使用案例](https://aws.amazon.com/blogs/mobile/building-a-graphql-api-with-java-and-aws-lambda/)。此使用案例與 DynamoDB 區段中展示的使用案例略有相似。在此應用程式中，GraphQL API 負責定義物件的操作，例如新增文章 （變動） 和擷取該資料 （查詢）。為了實作其操作的功能 （例如 `getPost ( id: String ! ) : Post`、`getPostsByAuthor ( author: String ! ) : [ Post ]`)，他們使用 Lambda 函數來處理傳入請求。在*選項 2： AWS AppSync 搭配 Lambda 解析程式*下，他們使用 AWS AppSync 服務來維護其結構描述，並將 Lambda 資料來源連結至其中一個操作。呼叫 操作時，Lambda 會與 Amazon RDS Proxy 連接，以在資料庫上執行業務邏輯。

### Amazon RDS
<a name="data-source-type-RDS"></a>

Amazon RDS 可讓您快速建置和設定關聯式資料庫。在 Amazon RDS 中，您將建立一般**資料庫執行個體**，做為雲端中隔離的資料庫環境。在此執行個體中，您將使用 **資料庫引擎**，這是實際的 RDBMS 軟體 (PostgreSQL、MySQL 等）。此服務使用 AWS基礎設施、修補和加密等安全服務，以及降低部署的管理成本，來卸載大部分後端工作。

從 Lambda 區段取得相同的[使用案例](https://aws.amazon.com/blogs/mobile/building-a-graphql-api-with-java-and-aws-lambda/)。在*選項 3： AWS AppSync 使用 Amazon RDS 解析程式*下，顯示的另一個選項是直接將 中的 GraphQL API 連結至 AWS AppSync Amazon RDS。使用[資料 API](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/data-api.html)，它們會將資料庫與 GraphQL API 建立關聯。解析程式會連接到欄位 （通常是查詢、變動或訂閱），並實作存取資料庫所需的 SQL 陳述式。當用戶端發出呼叫 欄位的請求時，解析程式會執行陳述式並傳回回應。

### Amazon EventBridge
<a name="data-source-type-eventbridge"></a>

在 EventBridge 中，您將建立**事件匯流排**，這是從您連接的服務或應用程式 (**事件來源**) 接收事件，並根據一組規則處理事件的管道。**事件**是執行環境中的一些狀態變更，而**規則**是事件的一組篩選條件。規則遵循**事件模式**或事件狀態變更的中繼資料 (id、區域、帳戶號碼、ARN (s) 等）。當事件符合事件模式時，EventBridge 會將整個管道的事件傳送至目的地服務 (**目標**)，並觸發規則中指定的動作。

EventBridge 非常適合將變更狀態的操作路由到其他一些 服務。從*前端 Web 和行動部落格*取得此[使用案例](https://aws.amazon.com/blogs/mobile/appsync-eventbridge/)。此範例描述的電子商務解決方案有數個團隊維護不同的服務。這些服務之一會在前端交付的每個步驟 （下單、進行中、運送、交付等） 為客戶提供訂單更新。不過，管理此服務的前端團隊無法直接存取排序系統資料，因為這是由個別後端團隊所維護。後端團隊的排序系統也被描述為黑色方塊，因此很難收集有關他們建構資料的方式的資訊。不過，後端團隊確實設定了一個系統，透過 EventBridge 管理的事件匯流排發佈訂單資料。為了存取來自事件匯流排的資料並將其路由到前端，前端團隊建立了指向其 GraphQL API 的新目標 AWS AppSync。他們也建立了規則，只傳送與訂單更新相關的資料。進行更新時，來自事件匯流排的資料會傳送至 GraphQL API。API 中的結構描述會處理資料，然後將其傳遞至前端。

### 無資料來源
<a name="data-source-type-none"></a>

如果您不打算使用資料來源，您可以將其設定為 `none`。雖然`none`資料來源仍明確分類為資料來源，但 不是儲存媒體。一般而言，解析程式會在某個時間點調用一或多個資料來源來處理請求。不過，在某些情況下，您可能不需要操作資料來源。將資料來源設定為 `none` 將執行請求、略過資料調用步驟，然後執行回應。

從 EventBridge 區段取得相同的[使用案例](https://aws.amazon.com/blogs/mobile/appsync-eventbridge/)。在結構描述中，變動會處理狀態更新，然後將其傳送給訂閱者。回顧解析程式的運作方式，通常至少有一個資料來源調用。不過，此案例中的資料已由事件匯流排自動傳送。這表示不需要變動來執行資料來源叫用；訂單狀態可以直接在本機處理。變動設定為 `none`，可做為沒有資料來源調用的傳遞值。然後，結構描述會填入傳送給訂閱者的資料。

### OpenSearch
<a name="data-source-type-opensearch"></a>

Amazon OpenSearch Service 是一套工具，可實作全文搜尋、資料視覺化和記錄。您可以使用此服務來查詢您上傳的結構化資料。

在此服務中，您將建立 OpenSearch 的執行個體。這些稱為**節點**。在節點中，您將新增至少一個**索引**。在概念上，索引有點像關聯式資料庫中的資料表。（不過，OpenSearch 不符合 ACID 規範，因此不應以此方式使用）。您將使用上傳到 OpenSearch 服務的資料填入索引。上傳資料時，資料將會以索引中存在的一或多個碎片編製索引。**碎片**就像索引的分割區，其中包含一些資料，可以與其他碎片分開查詢。上傳後，您的資料會建構為稱為 **文件**的 JSON 檔案。然後，您可以查詢節點以取得文件中的資料。

### HTTP 端點
<a name="data-source-type-http"></a>

您可以使用 HTTP 端點做為資料來源。 AWS AppSync 可以傳送請求到具有參數和承載等相關資訊的端點。HTTP 回應將公開給解析程式，該解析程式會在完成其 （操作） 操作後傳回最終回應。

## 新增資料來源
<a name="adding-a-data-source"></a>

如果您建立了資料來源，您可以將其連結至 AWS AppSync 服務，更具體地說是 API。

------
#### [ Console ]

1. 登入 AWS 管理主控台 並開啟 [AppSync 主控台](https://console.aws.amazon.com/appsync/)。

   1. 在**儀表板**中選擇您的 API。

   1. 在**側邊欄中**，選擇**資料來源**。

1. 選擇 **Create data source (建立資料來源)**。

   1. 為您的資料來源命名。您也可以提供描述，但這是選用的。

   1. 選擇您的**資料來源類型**。

   1. 對於 DynamoDB，您必須選擇您的區域，然後選擇區域中的資料表。您可以選擇建立新的一般資料表角色或匯入資料表的現有角色，以指定與資料表的互動規則。您可以啟用[版本控制](https://docs.aws.amazon.com/appsync/latest/devguide/conflict-detection-and-sync.html)，當多個用戶端同時嘗試更新資料時，它可以為每個請求自動建立資料版本。版本控制用於保留和維護多個資料變體，以用於偵測和解決衝突。您也可以啟用自動產生結構描述，這會取得資料來源，並產生在結構描述中存取它所需的一些 CRUD、 `List`和 `Query`操作。

      對於 OpenSearch，您必須選擇您的區域，然後選擇區域中的網域 （叢集）。您可以選擇建立新的一般資料表角色或匯入資料表的現有角色，以指定與網域的互動規則。

      對於 Lambda，您必須選擇您的區域，然後選擇區域中 Lambda 函數的 ARN。您可以選擇建立新的一般資料表角色或匯入資料表的現有角色，以指定與 Lambda 函數的互動規則。

      針對 HTTP，您必須輸入 HTTP 端點。

      對於 EventBridge，您必須選擇您的區域，然後選擇區域中的事件匯流排。您可以選擇建立新的一般資料表角色或匯入資料表的現有角色，以指定與事件匯流排的互動規則。

      對於 RDS，您必須選擇您的區域，然後選擇秘密存放區 （使用者名稱和密碼）、資料庫名稱和結構描述。

      對於無，您將新增沒有實際資料來源的資料來源。這是用於在本機處理解析程式，而不是透過實際的資料來源。
**注意**  
如果您要匯入現有的角色，他們需要信任政策。如需詳細資訊，請參閱 [IAM 信任政策](#iam-trust-policy.title)。

1. 選擇**建立**。
**注意**  
或者，如果您要建立 DynamoDB 資料來源，您可以前往主控台中的**結構描述**頁面，選擇頁面頂端的**建立資源**，然後填寫預先定義的模型以轉換為資料表。在此選項中，您將填寫或匯入基本類型、設定包含分割區索引鍵的基本資料表資料，以及檢閱結構描述變更。

------
#### [ CLI ]
+ 執行 [https://docs.aws.amazon.com/cli/latest/reference/appsync/create-data-source.html](https://docs.aws.amazon.com/cli/latest/reference/appsync/create-data-source.html)命令來建立資料來源。

  您需要為此特定命令輸入幾個參數：

  1. 您 API `api-id`的 。

  1. 資料表`name`的 。

  1. 資料來源`type`的 。視您選擇的資料來源類型而定，您可能需要輸入 `service-role-arn`和 `-config`標籤。

  範例命令可能如下所示：

  ```
   aws appsync create-data-source --api-id abcdefghijklmnopqrstuvwxyz --name data_source_name --type data_source_type --service-role-arn arn:aws:iam::107289374856:role/role_name --[data_source_type]-config {params}
  ```

------
#### [ CDK ]

**提示**  
在使用 CDK 之前，我們建議您檢閱 CDK 的[官方文件](https://docs.aws.amazon.com/cdk/v2/guide/home.html)以及 CDK AWS AppSync參考。 [https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html)  
下列步驟只會顯示用來新增特定資源之程式碼片段的一般範例。這**並非**您生產程式碼中的工作解決方案。我們也假設您已經有運作中的應用程式。

若要新增特定資料來源，您需要將 建構新增至堆疊檔案。您可以在這裡找到資料來源類型的清單：
+  [ DynamoDbDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.DynamoDbDataSource.html) 
+  [ EventBridgeDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.EventBridgeDataSource.html) 
+  [ HttpDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.HttpDataSource.html) 
+  [ LambdaDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.LambdaDataSource.html) 
+  [ NoneDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.NoneDataSource.html) 
+  [ OpenSearchDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.OpenSearchDataSource.html) 
+  [ RdsDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.RdsDataSource.html) 

1. 一般而言，您可能需要將匯入指令新增至您正在使用的服務。例如，它可能會遵循以下表單：

   ```
   import * as x from 'x'; # import wildcard as the 'x' keyword from 'x-service'
   import {a, b, ...} from 'c'; # import {specific constructs} from 'c-service'
   ```

   例如，以下是您可以匯入 AWS AppSync 和 DynamoDB 服務的方式：

   ```
   import * as appsync from 'aws-cdk-lib/aws-appsync';
   import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
   ```

1. 某些像 RDS 的服務在建立資料來源 （例如，VPC 建立、角色和存取憑證） 之前，需要在堆疊檔案中進行一些額外的設定。如需詳細資訊，請參閱相關 CDK 頁面中的範例。

1. 對於大多數資料來源，特別是 AWS 服務，您將在堆疊檔案中建立新的資料來源執行個體。一般而言，這看起來會如下所示：

   ```
   const add_data_source_func = new service_scope.resource_name(scope: Construct, id: string, props: data_source_props);
   ```

   例如，以下是 Amazon DynamoDB 資料表範例：

   ```
   const add_ddb_table = new dynamodb.Table(this, 'Table_ID', {
     partitionKey: {
       name: 'id',
       type: dynamodb.AttributeType.STRING,
     },
     sortKey: {
       name: 'id',
       type: dynamodb.AttributeType.STRING,
     },
     tableClass: dynamodb.TableClass.STANDARD,
   });
   ```
**注意**  
大多數資料來源至少會有一個必要的道具 (**將沒有**`?`符號表示）。請參閱 CDK 文件，了解需要哪些道具。

1. 接著，您需要將資料來源連結至 GraphQL API。建議的方法是在為管道解析程式建立函數時新增它。例如，以下程式碼片段是掃描 DynamoDB 資料表中所有元素的函數：

   ```
   const add_func = new appsync.AppsyncFunction(this, 'func_ID', {
     name: 'func_name_in_console',
     add_api,
     dataSource: add_api.addDynamoDbDataSource('data_source_name_in_console', add_ddb_table),
     code: appsync.Code.fromInline(`
         export function request(ctx) {
           return { operation: 'Scan' };
         }
   
         export function response(ctx) {
           return ctx.result.items;
         }
     `),
     runtime: appsync.FunctionRuntime.JS_1_0_0,
   });
   ```

   在`dataSource`道具中，您可以呼叫 GraphQL API (`add_api`)，並使用其中一個內建方法 (`addDynamoDbDataSource`) 建立資料表與 GraphQL API 之間的關聯。引數是將存在於 AWS AppSync 主控台 (`data_source_name_in_console`在此範例中為 ) 和資料表方法 () 中的此連結名稱`add_ddb_table`。當您開始建立解析程式時，將在下一節中顯示有關此主題的更多資訊。

   有替代方法來連結資料來源。您可以在技術上`api`新增至資料表函數中的道具清單。例如，以下是步驟 3 的程式碼片段，但具有包含 `api` GraphQL API 的 props：

   ```
   const add_api = new appsync.GraphqlApi(this, 'API_ID', {
     ...
   });
   
   const add_ddb_table = new dynamodb.Table(this, 'Table_ID', {
   
    ...
   
     api: add_api
   });
   ```

   或者，您可以分別呼叫`GraphqlApi`建構：

   ```
   const add_api = new appsync.GraphqlApi(this, 'API_ID', {
     ...
   });
   
   const add_ddb_table = new dynamodb.Table(this, 'Table_ID', {
     ...
   });
   
   const link_data_source = add_api.addDynamoDbDataSource('data_source_name_in_console', add_ddb_table);
   ```

   我們建議只在函數的道具中建立關聯。否則，您必須在 AWS AppSync 主控台中手動將解析程式函數連結至資料來源 （如果您想要繼續使用主控台值 `data_source_name_in_console`)，或在函數中以其他名稱建立個別的關聯，例如 `data_source_name_in_console_2`。這是因為道具處理資訊的方式受到限制。
**注意**  
您必須重新部署應用程式，才能查看您的變更。

------

### IAM 信任政策
<a name="iam-trust-policy"></a>

如果您為資料來源使用現有的 IAM 角色，則需要授予該角色適當的許可，以對 AWS 資源執行操作，例如在 Amazon DynamoDB 資料表`PutItem`上執行操作。您也需要修改該角色的信任政策，以允許 AWS AppSync 將其用於資源存取，如下列範例政策所示：

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

****  

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

------

您也可以將條件新增至信任政策，以視需要限制對資料來源的存取。目前， `SourceArn` 和 `SourceAccount`金鑰可用於這些條件。例如，下列政策會將對資料來源的存取限制在帳戶 `123456789012`：

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

****  

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

------

或者，您可以使用下列政策`abcdefghijklmnopq`，將資料來源的存取限制為特定 API，例如 ：

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

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "appsync.amazonaws.com"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "ArnEquals": {
          "aws:SourceArn": "arn:aws:appsync:us-west-2:123456789012:apis/abcdefghijklmnopq"
        }
      }
    }
  ]
}
```

------

您可以使用`us-east-1`下列政策，限制從特定區域存取 all AWS AppSync APIs，例如 ：

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

****  

```
{
  "Version":"2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "appsync.amazonaws.com"
      },
      "Action": "sts:AssumeRole",
      "Condition": {
        "ArnEquals": {
          "aws:SourceArn": "arn:aws:appsync:us-east-1:123456789012:apis/*"
        }
      }
    }
  ]
}
```

------

在下一節 ([設定解析程式](https://docs.aws.amazon.com//appsync/latest/devguide/resolver-config-overview.html)) 中，我們將新增解析程式商業邏輯，並將其連接到結構描述中的欄位，以處理資料來源中的資料。

如需角色政策組態的詳細資訊，請參閱《*IAM 使用者指南*》中的[修改角色](https://docs.aws.amazon.com//IAM/latest/UserGuide/id_roles_manage_modify.html)。

如需 AWS Lambda 解析程式 for AWS AppSync 跨帳戶存取的詳細資訊，請參閱[建置跨帳戶 AWS Lambda 解析程式 for AWS AppSync](https://aws.amazon.com/blogs/mobile/appsync-lambda-cross-account/)。

# 在 中設定解析程式 AWS AppSync
<a name="resolver-config-overview"></a>

在前幾節中，您已了解如何建立 GraphQL 結構描述和資料來源，然後在 AWS AppSync 服務中將這些結構描述和資料來源連結在一起。在您的結構描述中，您可能已在查詢和變動中建立一或多個欄位 （操作）。雖然結構描述描述了操作從資料來源請求的資料類型，但它從未實作這些操作在資料方面的行為。

操作的行為一律會在解析程式中實作，這會連結到執行操作的欄位。如需解析程式如何正常運作的詳細資訊，請參閱[解析程式](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-components.html)頁面。

在 中 AWS AppSync，您的解析程式會繫結至執行時間，這是解析程式執行的環境。執行時間會指定您的解析程式將寫入的語言。目前支援兩種執行時間：APPSYNC\$1JS (JavaScript) 和 Apache Velocity 範本語言 (VTL)。

實作解析程式時，會遵循一般結構：
+ 在**步驟之前**：當用戶端提出請求時，所使用結構描述欄位的解析程式 （通常是您的查詢、變動、訂閱） 會傳遞請求資料。解析程式會開始處理使用步驟前處理常式的請求資料，這允許在資料通過解析程式之前執行一些預先處理操作。
+ **Function(s)**：在步驟執行之前，請求會傳遞至函數清單。清單中的第一個函數將針對資料來源執行。函數是解析程式程式碼的子集，其中包含自己的請求和回應處理常式。請求處理常式會取得請求資料，並對資料來源執行操作。回應處理常式會先處理資料來源的回應，再將其傳回清單。如果有多個函數，請求資料將傳送至清單中要執行的下一個函數。清單中的函數將依開發人員定義的順序序列執行。執行所有函數後，最終結果會傳遞至步驟後 。
+ **後步驟**：後步驟是處理常式函數，可讓您在最終函數的回應上執行一些最終操作，然後再將其傳遞至 GraphQL 回應。

此流程是管道解析程式的範例。兩個執行時間都支援管道解析程式。不過，這是管道解析程式可以執行的操作的簡化說明。此外，我們只描述一個可能的解析程式組態。如需支援的解析程式組態的詳細資訊，請參閱 APPSYNC\$1JS 的 [JavaScript 解析程式概觀](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html)或 VTL 的[解析程式映射範本概觀](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-mapping-template-reference-overview.html)。

如您所見，解析程式是模組化的。為了讓解析程式的元件正常運作，它們必須能夠對等其他元件的執行狀態。從[解析程式](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-components.html)區段中，您知道解析程式中的每個元件都可以作為一組引數 (`args`、 `context`等） 傳遞有關執行狀態的重要資訊。在 中 AWS AppSync，這由 嚴格處理`context`。這是要解析之欄位資訊的容器。這可以包含來自傳遞引數、結果、授權資料、標頭資料等的所有內容。如需內容的詳細資訊，請參閱 APPSYNC\$1JS 的 [Resolver 內容物件參考](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html)或 VTL 的 [Resolver 映射範本內容參考](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference.html)。

內容並非您可用來實作解析程式的唯一工具。 AWS AppSync 支援各種公用程式，可用於產生價值、處理錯誤、剖析、轉換等。您可以在[此處](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference-js.html)查看 APPSYNC\$1JS 的公用程式清單，或是 [VTL](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference.html) 的公用程式清單。

在下列各節中，您將了解如何在 GraphQL API 中設定解析程式。

**Topics**
+ [建立基本查詢 (JavaScript)](configuring-resolvers-js.md)
+ [建立基本查詢 (VTL)](configuring-resolvers.md)

# 建立基本查詢 (JavaScript)
<a name="configuring-resolvers-js"></a>

GraphQL 解析程式將類型結構描述中的欄位連接到資料來源。解析程式是滿足請求的機制。

Resolvers in AWS AppSync 使用 JavaScript 將 GraphQL 表達式轉換為資料來源可以使用的格式。或者，映射範本可以用 [Apache Velocity 範本語言 (VTL)](https://velocity.apache.org/engine/2.0/vtl-reference.html) 撰寫，將 GraphQL 表達式轉換為資料來源可以使用的格式。

本節說明如何使用 JavaScript 設定解析程式。[Resolver 教學課程 (JavaScript)](https://docs.aws.amazon.com/appsync/latest/devguide/tutorials-js.html) 區段提供如何使用 JavaScript 實作解析程式的深入教學課程。[Resolver 參考 (JavaScript)](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-js-version.html) 區段提供可搭配 JavaScript 解析程式使用的公用程式操作說明。

我們建議您先遵循本指南，再嘗試使用上述任何教學課程。

在本節中，我們將逐步解說如何建立和設定查詢和變動的解析程式。

**注意**  
本指南假設您已建立結構描述，並且至少有一個查詢或變動。如果您要尋找訂閱 （即時資料），請參閱[本指南](https://docs.aws.amazon.com/appsync/latest/devguide/aws-appsync-real-time-data.html)。

在本節中，我們將提供一些設定解析程式的一般步驟，以及使用下列結構描述的範例：

```
// schema.graphql file

input CreatePostInput {
  title: String
  date: AWSDateTime
}

type Post {
  id: ID!
  title: String
  date: AWSDateTime
}

type Mutation {
  createPost(input: CreatePostInput!): Post
}

type Query {
  getPost: [Post]
}
```

## 建立基本查詢解析程式
<a name="create-basic-query-resolver-js"></a>

本節將說明如何建立基本查詢解析程式。

------
#### [ Console ]

1. 登入 AWS 管理主控台 並開啟 [AppSync 主控台](https://console.aws.amazon.com/appsync/)。

   1. 在 **APIs儀表板**中，選擇您的 GraphQL API。

   1. 在**側邊欄中**，選擇**結構描述**。

1. 輸入結構描述和資料來源的詳細資訊。如需詳細資訊，請參閱[設計您的結構描述](https://docs.aws.amazon.com/appsync/latest/devguide/designing-your-schema.html)和[連接資料來源](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html)一節。

1. 在**結構描述**編輯器旁邊，有一個稱為**解析程式**的視窗。此方塊包含**結構描述**視窗中定義的類型和欄位清單。您可以將解析程式連接至欄位。您很可能將解析程式連接到您的欄位操作。在本節中，我們將介紹簡單的查詢組態。在**查詢**類型下，選擇查詢欄位旁的**連接**。

1. 在**連接解析程式**頁面的**解析程式類型**下，您可以選擇管道或單位解析程式。如需這些類型的詳細資訊，請參閱[解析程式](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-components.html)。本指南將使用 `pipeline resolvers`。
**提示**  
建立管道解析程式時，您的資料來源會連接到管道函數 (s)。函數會在您建立管道解析程式本身後建立，因此此頁面中沒有設定它的選項。如果您使用的是單位解析程式，則資料來源會直接繫結至解析程式，因此您會在此頁面上設定。

   針對**解析程式執行時間**，選擇`APPSYNC_JS`啟用 JavaScript 執行時間。

1. 您可以為此 API 啟用[快取](https://docs.aws.amazon.com/appsync/latest/devguide/enabling-caching.html)。我們建議您立即關閉此功能。選擇**建立**。

1. 在**編輯解析程式**頁面上，有一個稱為**解析程式程式碼**的程式碼編輯器，可讓您實作解析程式處理常式和回應的邏輯 （步驟前後）。如需詳細資訊，請參閱 [JavaScript 解析程式概觀](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html)。
**注意**  
在我們的範例中，我們只會將請求保留空白，並將回應設定為從[內容](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html)傳回最後一個資料來源結果：  

   ```
   import {util} from '@aws-appsync/utils';
   
   export function request(ctx) {
       return {};
   }
   
   export function response(ctx) {
       return ctx.prev.result;
   }
   ```

   在本節下方，有一個名為 **Functions 的**資料表。函數可讓您實作可在多個解析程式間重複使用的程式碼。您可以視需要將原始程式碼儲存為新增至解析程式的函數，而不是持續重寫或複製程式碼。

   函數構成管道操作清單的大量內容。在解析程式中使用多個函數時，您可以設定函數的順序，它們將按該順序執行。它們會在請求函數執行後和回應函數開始之前執行。

   若要新增函數，請在**函數**下選擇**新增函數**，然後選擇**建立新函數**。或者，您可能會看到**建立函數**按鈕來選擇。

   1. 選擇資料來源。這將是解析程式對其執行動作的資料來源。
**注意**  
在我們的範例中，我們正在連接 的解析程式`getPost`，它會透過 擷取`Post`物件`id`。假設我們已為此結構描述設定 DynamoDB 資料表。其分割區索引鍵設定為 `id`，且為空白。

   1. 輸入 `Function name`。

   1. 在**函數程式碼**下，您需要實作函數的行為。這可能令人困惑，但每個函數都有自己的本機請求和回應處理常式。請求會執行，然後進行資料來源調用來處理請求，然後由回應處理常式處理資料來源回應。結果會存放在[內容](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html)物件中。之後，清單中的下一個函數會執行，如果是最後一個函數，則會傳遞至步驟後回應處理常式。
**注意**  
在我們的範例中，我們會將解析程式連接至 `getPost`，從資料來源取得`Post`物件清單。我們的請求函數會從我們的資料表請求資料，資料表會將其回應傳遞至內容 (ctx)，然後回應會在內容中傳回結果。 AWS AppSync的強度在於其與其他 AWS 服務的互連性。由於我們使用 DynamoDB，因此我們有[一套操作](https://docs.aws.amazon.com/appsync/latest/devguide/js-resolver-reference-dynamodb.html)來簡化這類操作。我們也有一些其他資料來源類型的樣板範例。  
我們的程式碼如下所示：  

      ```
      import { util } from '@aws-appsync/utils';
      
      /**
       * Performs a scan on the dynamodb data source
       */
      export function request(ctx) {
        return { operation: 'Scan' };
      }
      
      /**
       * return a list of scanned post items
       */
      export function response(ctx) {
        return ctx.result.items;
      }
      ```
在此步驟中，我們新增了兩個函數：  
`request`：請求處理常式會對資料來源執行擷取操作。引數包含內容物件 (`ctx`) 或一些資料，可供執行特定操作的所有解析程式使用。例如，它可能包含授權資料、要解析的欄位名稱等。傳回陳述式會執行 [https://docs.aws.amazon.com//appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-scan](https://docs.aws.amazon.com//appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-scan)操作 （如需範例，請參閱[此處](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Scan.html))。由於我們使用 DynamoDB，因此我們可以使用該服務的一些操作。掃描會執行資料表中所有項目的基本擷取。此操作的結果會存放在內容物件中做為`result`容器，再傳遞給回應處理常式。在管道中的回應之前`request`執行 。
`response`：傳回 輸出的回應處理常式`request`。引數是更新的內容物件，而傳回陳述式是 `ctx.prev.result`。在本指南的這個階段，您可能不熟悉此值。 `ctx`是指內容物件。 `prev`是指管道中先前的操作，也就是我們的 `request`。`result` 包含解析程式在管道中移動時的結果 (s)。如果您將所有操作放在一起， `ctx.prev.result` 會傳回上次執行的操作結果，也就是請求處理常式。

   1. 完成後，請選擇**建立**。

1. 返回解析程式畫面的**函數**下，選擇**新增函數**下拉式清單，並將函數新增至函數清單。

1. 選擇**儲存**以更新解析程式。

------
#### [ CLI ]

**新增您的 函數**
+ 使用 `[create-function](https://docs.aws.amazon.com/cli/latest/reference/appsync/create-function.html)`命令為您的管道解析程式建立 函數。

  您需要為此特定命令輸入幾個參數：

  1. 您 API `api-id`的 。

  1.  AWS AppSync 主控台中`name`函數的 。

  1. 函數將使用的資料來源名稱 `data-source-name`或 。它必須已在 AWS AppSync 服務中建立並連結至您的 GraphQL API。

  1. 函數的 `runtime`、 或 環境和語言。對於 JavaScript，名稱必須為 `APPSYNC_JS`，執行期為 `1.0.0`。

  1. 函數的 `code`、 或 請求和回應處理常式。雖然您可以手動輸入，但將其新增至 .txt 檔案 （或類似格式），然後將其做為引數傳入會更為容易。
**注意**  
我們的查詢程式碼將位於傳入為引數的檔案中：  

     ```
     import { util } from '@aws-appsync/utils';
     
     /**
      * Performs a scan on the dynamodb data source
      */
     export function request(ctx) {
       return { operation: 'Scan' };
     }
     
     /**
      * return a list of scanned post items
      */
     export function response(ctx) {
       return ctx.result.items;
     }
     ```

  範例命令可能如下所示：

  ```
  aws appsync create-function \
  --api-id abcdefghijklmnopqrstuvwxyz \
  --name get_posts_func_1 \
  --data-source-name table-for-posts \
  --runtime name=APPSYNC_JS,runtimeVersion=1.0.0 \
  --code file://~/path/to/file/{filename}.{fileType}
  ```

  輸出會在 CLI 中傳回。範例如下：

  ```
  {
      "functionConfiguration": {
          "functionId": "ejglgvmcabdn7lx75ref4qeig4",
          "functionArn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/functions/ejglgvmcabdn7lx75ref4qeig4",
          "name": "get_posts_func_1",
          "dataSourceName": "table-for-posts",
          "maxBatchSize": 0,
          "runtime": {
              "name": "APPSYNC_JS",
              "runtimeVersion": "1.0.0"
          },
          "code": "Code output goes here"
      }
  }
  ```
**注意**  
請務必在`functionId`某處記錄 ，因為這將用於將函數連接至解析程式。

**建立您的解析程式**
+ 執行 `[create-resolver](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html)`命令`Query`，為 建立管道函數。

  您需要為此特定命令輸入幾個參數：

  1. 您 API `api-id`的 。

  1. `type-name`結構描述中的 或特殊物件類型 （查詢、變動、訂閱）。

  1. 在您欲連接解析程式之特殊物件類型內的 `field-name`或 欄位操作。

  1. `kind`，指定單位或管道解析程式。將此設為 `PIPELINE`以啟用管道函數。

  1. 要連接到解析程式的 (`pipeline-config`或） 函數。請確定您知道函數`functionId`的值。列出順序很重要。

  1. `runtime`，也就是 `APPSYNC_JS`(JavaScript)。`runtimeVersion` 目前為 `1.0.0`。

  1. `code`，其中包含步驟處理常式前後的 。
**注意**  
我們的查詢程式碼將位於傳入為引數的檔案中：  

     ```
     import { util } from '@aws-appsync/utils';
     
     /**
      * Sends a request to `put` an item in the DynamoDB data source
      */
     export function request(ctx) {
       const { id, ...values } = ctx.args;
       return {
         operation: 'PutItem',
         key: util.dynamodb.toMapValues({ id }),
         attributeValues: util.dynamodb.toMapValues(values),
       };
     }
     
     /**
      * returns the result of the `put` operation
      */
     export function response(ctx) {
       return ctx.result;
     }
     ```

  範例命令可能如下所示：

  ```
  aws appsync create-resolver \
  --api-id abcdefghijklmnopqrstuvwxyz \
  --type-name Query \
  --field-name getPost \
  --kind PIPELINE \
  --pipeline-config functions=ejglgvmcabdn7lx75ref4qeig4 \
  --runtime name=APPSYNC_JS,runtimeVersion=1.0.0 \
  --code file:///path/to/file/{filename}.{fileType}
  ```

  輸出會在 CLI 中傳回。範例如下：

  ```
  {
      "resolver": {
          "typeName": "Mutation",
          "fieldName": "getPost",
          "resolverArn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Mutation/resolvers/getPost",
          "kind": "PIPELINE",
          "pipelineConfig": {
              "functions": [
                  "ejglgvmcabdn7lx75ref4qeig4"
              ]
          },
          "maxBatchSize": 0,
          "runtime": {
              "name": "APPSYNC_JS",
              "runtimeVersion": "1.0.0"
          },
          "code": "Code output goes here"
      }
  }
  ```

------
#### [ CDK ]

**提示**  
在使用 CDK 之前，我們建議您檢閱 CDK 的[官方文件](https://docs.aws.amazon.com/cdk/v2/guide/home.html)以及 CDK AWS AppSync參考。 [https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html)  
下列步驟只會顯示用來新增特定資源之程式碼片段的一般範例。這**並非**您生產程式碼中的工作解決方案。我們也假設您已經有運作中的應用程式。

基本應用程式將需要下列項目：

1. 服務匯入指令

1. 結構描述程式碼

1. 資料來源產生器

1. 函數程式碼

1. 解析程式程式碼

從[設計您的結構描述](https://docs.aws.amazon.com/appsync/latest/devguide/designing-your-schema.html)和[連接資料來源](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html)區段中，我們知道堆疊檔案將包含格式的匯入指令：

```
import * as x from 'x'; # import wildcard as the 'x' keyword from 'x-service'
import {a, b, ...} from 'c'; # import {specific constructs} from 'c-service'
```

**注意**  
在先前的章節中，我們只說明了如何匯入 AWS AppSync 建構。在真實程式碼中，您必須匯入更多服務，才能執行應用程式。在我們的範例中，如果我們要建立非常簡單的 CDK 應用程式，我們至少會匯入 AWS AppSync 服務與資料來源，也就是 DynamoDB 資料表。我們還需要匯入一些額外的建構，才能部署應用程式：  

```
import * as cdk from 'aws-cdk-lib';
import * as appsync from 'aws-cdk-lib/aws-appsync';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import { Construct } from 'constructs';
```
若要摘要下列各項：  
`import * as cdk from 'aws-cdk-lib';`：這可讓您定義 CDK 應用程式和建構，例如堆疊。它還包含一些實用的公用程式函數，適用於我們的應用程式，例如操作中繼資料。如果您熟悉此匯入指令，但想知道為何此處未使用 cdk 核心程式庫，請參閱[遷移](https://docs.aws.amazon.com/cdk/v2/guide/migrating-v2.html)頁面。
`import * as appsync from 'aws-cdk-lib/aws-appsync';`：這會匯入[AWS AppSync 服務](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html)。
`import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';`：這會匯入 [DynamoDB 服務](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_dynamodb-readme.html)。
`import { Construct } from 'constructs';`：我們需要此項目來定義根[建構](https://docs.aws.amazon.com/cdk/v2/guide/constructs.html)。

匯入的類型取決於您呼叫的服務。我們建議您查看 CDK 文件以取得範例。頁面頂端的結構描述將是 CDK 應用程式中的個別檔案，做為 `.graphql` 檔案。在堆疊檔案中，我們可以使用下列格式將其與新的 GraphQL 建立關聯：

```
const add_api = new appsync.GraphqlApi(this, 'graphQL-example', {
  name: 'my-first-api',
  schema: appsync.SchemaFile.fromAsset(path.join(__dirname, 'schema.graphql')),
});
```

**注意**  
在範圍 中`add_api`，我們使用`new`關鍵字後面接著 來新增 GraphQL API`appsync.GraphqlApi(scope: Construct, id: string , props: GraphqlApiProps)`。我們的範圍是 `this`，CFN id 是 `graphQL-example`，而我們的道具是 `my-first-api`（主控台中 API 的名稱） 和 `schema.graphql`（結構描述檔案的絕對路徑）。

若要新增資料來源，您必須先將資料來源新增至堆疊。然後，您需要使用來源特定方法將其與 GraphQL API 建立關聯。當您建立解析程式函數時，就會發生關聯。同時，讓我們使用 建立 DynamoDB 資料表的範例`dynamodb.Table`：

```
const add_ddb_table = new dynamodb.Table(this, 'posts-table', {
  partitionKey: {
    name: 'id',
    type: dynamodb.AttributeType.STRING,
  },
});
```

**注意**  
如果我們在範例中使用此值，則會新增 CFN ID 為 `posts-table`且分割區索引鍵為 的新 DynamoDB 資料表`id (S)`。

接下來，我們需要在堆疊檔案中實作解析程式。以下是掃描 DynamoDB 資料表中所有項目的簡單查詢範例：

```
const add_func = new appsync.AppsyncFunction(this, 'func-get-posts', {
  name: 'get_posts_func_1',
  add_api,
  dataSource: add_api.addDynamoDbDataSource('table-for-posts', add_ddb_table),
  code: appsync.Code.fromInline(`
      export function request(ctx) {
        return { operation: 'Scan' };
      }

      export function response(ctx) {
        return ctx.result.items;
      }
  `),
  runtime: appsync.FunctionRuntime.JS_1_0_0,
});

new appsync.Resolver(this, 'pipeline-resolver-get-posts', {
  add_api,
  typeName: 'Query',
  fieldName: 'getPost',
  code: appsync.Code.fromInline(`
      export function request(ctx) {
        return {};
      }

      export function response(ctx) {
        return ctx.prev.result;
      }
 `),
  runtime: appsync.FunctionRuntime.JS_1_0_0,
  pipelineConfig: [add_func],
});
```

**注意**  
首先，我們建立了名為 的函數`add_func`。此建立順序可能看起來有點反直覺，但您必須在管道解析程式中建立函數，才能建立解析程式本身。函數的形式如下：  

```
AppsyncFunction(scope: Construct, id: string, props: AppsyncFunctionProps)
```
我們的範圍是 `this`，我們的 CFN ID 是 `func-get-posts`，而我們的道具包含實際的函數詳細資訊。在道具內，我們包括：  
將出現在 AWS AppSync 主控台的 `name` 函數的 (`get_posts_func_1`)。
我們先前建立的 GraphQL API (`add_api`)。
資料來源；這是我們將資料來源連結至 GraphQL API 值，然後將其連接至函數的點。我們採用我們建立的資料表 (`add_ddb_table`)，並使用其中一種`GraphqlApi`方法 (`add_api`) 將其連接到 GraphQL API ()[https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.GraphqlApi.html#addwbrdynamowbrdbwbrdatawbrsourceid-table-options](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.GraphqlApi.html#addwbrdynamowbrdbwbrdatawbrsourceid-table-options)。ID 值 (`table-for-posts`) 是主控台中 AWS AppSync 資料來源的名稱。如需來源特定方法的清單，請參閱下列頁面：  
[ DynamoDbDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.DynamoDbDataSource.html) 
 [ EventBridgeDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.EventBridgeDataSource.html) 
 [ HttpDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.HttpDataSource.html) 
 [ LambdaDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.LambdaDataSource.html) 
 [ NoneDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.NoneDataSource.html) 
 [ OpenSearchDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.OpenSearchDataSource.html) 
 [ RdsDataSource ](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync.RdsDataSource.html) 
程式碼包含函數的請求和回應處理常式，這是簡單的掃描和傳回。
執行時間指定要使用 APPSYNC\$1JS 執行時間 1.0.0 版。請注意，目前這是 APPSYNC\$1JS 唯一可用的版本。
接下來，我們需要將 函數連接至管道解析程式。我們建立解析程式的方式如下：  

```
Resolver(scope: Construct, id: string, props: ResolverProps)
```
我們的範圍是 `this`，我們的 CFN ID 是 `pipeline-resolver-get-posts`，而我們的道具包含實際的函數詳細資訊。在道具中，我們包括：  
我們先前建立的 GraphQL API (`add_api`)。
特殊物件類型名稱；這是查詢操作，因此我們只會新增值 `Query`。
欄位名稱 (`getPost`) 是 `Query`類型下結構描述中的欄位名稱。
此程式碼包含處理常式前後的 。我們的範例只會傳回函數執行其操作後，內容中的任何結果。
執行時間指定要使用 APPSYNC\$1JS 執行時間 1.0.0 版。請注意，目前這是 APPSYNC\$1JS 唯一可用的版本。
管道組態包含我們所建立函數的參考 (`add_func`)。

------

為了摘要此範例中發生的情況，您看到了實作請求和回應處理常式的 AWS AppSync 函數。函數負責與您的資料來源互動。請求處理常式將 `Scan` 操作傳送到 AWS AppSync，指示它針對 DynamoDB 資料來源執行的操作。回應處理常式傳回項目清單 (`ctx.result.items`)。然後，項目清單會自動映射至 `Post` GraphQL 類型。

## 建立基本變動解析程式
<a name="creating-basic-mutation-resolvers-js"></a>

本節將說明如何建立基本的變動解析程式。

------
#### [ Console ]

1. 登入 AWS 管理主控台 並開啟 [AppSync 主控台](https://console.aws.amazon.com/appsync/)。

   1. 在 **APIs儀表板**中，選擇您的 GraphQL API。

   1. 在**側邊欄中**，選擇**結構描述**。

1. 在**解析程式**區段和**變動**類型下，選擇欄位旁的**連接**。
**注意**  
在我們的範例中，我們正在連接 的解析程式`createPost`，這會將`Post`物件新增至我們的資料表。假設我們使用上一節的相同 DynamoDB 資料表。其分割區索引鍵設定為 `id`，且為空白。

1. 在**連接解析程式**頁面的**解析程式類型**下，選擇 `pipeline resolvers`。提醒您，您可以[在這裡](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-components.html)找到有關解析程式的詳細資訊。針對**解析程式執行時間**，選擇 `APPSYNC_JS`以啟用 JavaScript 執行時間。

1. 您可以為此 API 啟用[快取](https://docs.aws.amazon.com/appsync/latest/devguide/enabling-caching.html)。我們建議您立即關閉此功能。選擇**建立**。

1. 選擇**新增函數**，然後選擇**建立新函數**。或者，您可能會看到**建立函數**按鈕來選擇。

   1. 選擇您的資料來源。這應該是您要使用變動操作資料的來源。

   1. 輸入 `Function name`。

   1. 在**函數程式碼**下，您需要實作函數的行為。這是一個變動，因此請求最好會對調用的資料來源執行一些狀態變更操作。結果將由回應函數處理。
**注意**  
`createPost` 正在新增或 "putting" 資料表`Post`中的新 ，並將我們的參數做為資料。我們可以新增如下內容：  

      ```
      import { util } from '@aws-appsync/utils';
      
      /**
       * Sends a request to `put` an item in the DynamoDB data source
       */
      export function request(ctx) {
        return {
          operation: 'PutItem',
          key: util.dynamodb.toMapValues({id: util.autoId()}),
          attributeValues: util.dynamodb.toMapValues(ctx.args.input),
        };
      }
      
      /**
       * returns the result of the `put` operation
       */
      export function response(ctx) {
        return ctx.result;
      }
      ```
在此步驟中，我們也新增了 `request`和 `response`函數：  
`request`：請求處理常式接受內容做為引數。請求處理常式傳回陳述式會執行 [https://docs.aws.amazon.com//appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-putitem](https://docs.aws.amazon.com//appsync/latest/devguide/js-resolver-reference-dynamodb.html#js-aws-appsync-resolver-reference-dynamodb-putitem)命令，這是內建的 DynamoDB 操作 （如需範例，請參閱[此處](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/getting-started-step-2.html)或[此處](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/WorkingWithItems.html#WorkingWithItems.WritingData))。`PutItem` 命令會採用分割區`key`值 （由 自動產生`util.autoid()`) 並從內容引數輸入 `attributes` （這些是我們將在請求中傳遞的值），將`Post`物件新增至 DynamoDB 資料表。`key` 是 `id`，而 `attributes`是 `date`和 `title` 欄位引數。它們都是透過[https://docs.aws.amazon.com//appsync/latest/devguide/dynamodb-helpers-in-util-dynamodb-js.html#utility-helpers-in-toMap-js](https://docs.aws.amazon.com//appsync/latest/devguide/dynamodb-helpers-in-util-dynamodb-js.html#utility-helpers-in-toMap-js)協助程式預先格式化，以使用 DynamoDB 資料表。
`response`：回應接受更新的內容，並傳回請求處理常式的結果。

   1. 完成後選擇**建立**。

1. 返回解析程式畫面的**函數**下，選擇**新增函數**下拉式清單，並將函數新增至函數清單。

1. 選擇**儲存**以更新解析程式。

------
#### [ CLI ]

**新增您的 函數**
+ 使用 `[create-function](https://docs.aws.amazon.com/cli/latest/reference/appsync/create-function.html)`命令為您的管道解析程式建立 函數。

  您需要為此特定命令輸入幾個參數：

  1. 您 API `api-id`的 。

  1.  AWS AppSync 主控台中`name`函數的 。

  1. `data-source-name`或 函數將使用的資料來源名稱。它必須已在 AWS AppSync 服務中建立並連結至您的 GraphQL API。

  1. 函數的 `runtime`、 或 環境和語言。對於 JavaScript，名稱必須為 `APPSYNC_JS`，執行期為 `1.0.0`。

  1. 函數的 `code`、 或 請求和回應處理常式。雖然您可以手動輸入，但將其新增至 .txt 檔案 （或類似格式），然後將其做為引數傳入會更為容易。
**注意**  
我們的查詢程式碼將位於傳入為引數的檔案中：  

     ```
     import { util } from '@aws-appsync/utils';
     
     /**
      * Sends a request to `put` an item in the DynamoDB data source
      */
     export function request(ctx) {
       return {
         operation: 'PutItem',
         key: util.dynamodb.toMapValues({id: util.autoId()}),
         attributeValues: util.dynamodb.toMapValues(ctx.args.input),
       };
     }
     
     /**
      * returns the result of the `put` operation
      */
     export function response(ctx) {
       return ctx.result;
     }
     ```

  範例命令可能如下所示：

  ```
  aws appsync create-function \
  --api-id abcdefghijklmnopqrstuvwxyz \
  --name add_posts_func_1 \
  --data-source-name table-for-posts \
  --runtime name=APPSYNC_JS,runtimeVersion=1.0.0 \
  --code file:///path/to/file/{filename}.{fileType}
  ```

  輸出會在 CLI 中傳回。範例如下：

  ```
  {
      "functionConfiguration": {
          "functionId": "vulcmbfcxffiram63psb4dduoa",
          "functionArn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/functions/vulcmbfcxffiram63psb4dduoa",
          "name": "add_posts_func_1",
          "dataSourceName": "table-for-posts",
          "maxBatchSize": 0,
          "runtime": {
              "name": "APPSYNC_JS",
              "runtimeVersion": "1.0.0"
          },
          "code": "Code output foes here"
      }
  }
  ```
**注意**  
請務必在`functionId`某處記錄 ，因為這將用於將函數連接至解析程式。

**建立您的解析程式**
+ `Mutation` 執行 `[create-resolver](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html)`命令來建立 的管道函數。

  您需要為此特定命令輸入幾個參數：

  1. 您 API `api-id`的 。

  1. 結構描述中的 `type-name`或特殊物件類型 （查詢、變動、訂閱）。

  1. 在您欲連接解析程式之特殊物件類型內的 `field-name`或 欄位操作。

  1. `kind`，指定單位或管道解析程式。將此設為 `PIPELINE`以啟用管道函數。

  1. 要連接到解析程式的 `pipeline-config`（或） 函數。請確定您知道函數`functionId`的值。列出 的順序很重要。

  1. `runtime`，也就是 `APPSYNC_JS`(JavaScript)。`runtimeVersion` 目前為 `1.0.0`。

  1. `code`，其中包含步驟前後的 。
**注意**  
我們的查詢程式碼將位於傳入為引數的檔案中：  

     ```
     import { util } from '@aws-appsync/utils';
     
     /**
      * Sends a request to `put` an item in the DynamoDB data source
      */
     export function request(ctx) {
       const { id, ...values } = ctx.args;
       return {
         operation: 'PutItem',
         key: util.dynamodb.toMapValues({ id }),
         attributeValues: util.dynamodb.toMapValues(values),
       };
     }
     
     /**
      * returns the result of the `put` operation
      */
     export function response(ctx) {
       return ctx.result;
     }
     ```

  範例命令可能如下所示：

  ```
  aws appsync create-resolver \
  --api-id abcdefghijklmnopqrstuvwxyz \
  --type-name Mutation \
  --field-name createPost \
  --kind PIPELINE \
  --pipeline-config functions=vulcmbfcxffiram63psb4dduoa \
  --runtime name=APPSYNC_JS,runtimeVersion=1.0.0 \
  --code file:///path/to/file/{filename}.{fileType}
  ```

  輸出會在 CLI 中傳回。範例如下：

  ```
  {
      "resolver": {
          "typeName": "Mutation",
          "fieldName": "createPost",
          "resolverArn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Mutation/resolvers/createPost",
          "kind": "PIPELINE",
          "pipelineConfig": {
              "functions": [
                  "vulcmbfcxffiram63psb4dduoa"
              ]
          },
          "maxBatchSize": 0,
          "runtime": {
              "name": "APPSYNC_JS",
              "runtimeVersion": "1.0.0"
          },
          "code": "Code output goes here"
      }
  }
  ```

------
#### [ CDK ]

**提示**  
在使用 CDK 之前，我們建議您檢閱 CDK 的[官方文件](https://docs.aws.amazon.com/cdk/v2/guide/home.html)以及 CDK AWS AppSync參考。 [https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html)  
下列步驟只會顯示用來新增特定資源之程式碼片段的一般範例。這**並非**您生產程式碼中的工作解決方案。我們也假設您已經有運作中的應用程式。
+ 若要進行變動，假設您在同一個專案中，您可以將它新增至堆疊檔案，例如查詢。以下是變動的修改函數和解析程式，會將新的 新增至`Post`資料表：

  ```
  const add_func_2 = new appsync.AppsyncFunction(this, 'func-add-post', {
    name: 'add_posts_func_1',
    add_api,
    dataSource: add_api.addDynamoDbDataSource('table-for-posts-2', add_ddb_table),
        code: appsync.Code.fromInline(`
            export function request(ctx) {
              return {
                operation: 'PutItem',
                key: util.dynamodb.toMapValues({id: util.autoId()}),
                attributeValues: util.dynamodb.toMapValues(ctx.args.input),
              };
            }
  
            export function response(ctx) {
              return ctx.result;
            }
        `), 
    runtime: appsync.FunctionRuntime.JS_1_0_0,
  });
  
  new appsync.Resolver(this, 'pipeline-resolver-create-posts', {
    add_api,
    typeName: 'Mutation',
    fieldName: 'createPost',
        code: appsync.Code.fromInline(`
            export function request(ctx) {
              return {};
            }
  
            export function response(ctx) {
              return ctx.prev.result;
            }
        `),
    runtime: appsync.FunctionRuntime.JS_1_0_0,
    pipelineConfig: [add_func_2],
  });
  ```
**注意**  
由於此變動和查詢結構類似，我們只會說明我們為了進行變動所做的變更。  
在 函數中，我們將 CFN ID 變更為 `func-add-post`，並將名稱變更為 `add_posts_func_1` ，以反映我們將`Posts`新增至資料表的事實。在資料來源中，我們在 AWS AppSync 主控台中與資料表 (`add_ddb_table`) 建立新的關聯，`table-for-posts-2`因為 `addDynamoDbDataSource`方法需要它。請記住，這個新的關聯仍在使用先前建立的相同資料表，但我們現在在 AWS AppSync 主控台中有兩個與其連線：一個用於查詢 ，`table-for-posts`另一個用於變動 `table-for-posts-2`。程式碼已變更為新增 ，`Post`方法是自動產生其`id`值，並接受用戶端對其餘欄位的輸入。  
在解析程式中，我們將 ID 值變更為 `pipeline-resolver-create-posts`，以反映我們將`Posts`新增至資料表的事實。為了反映結構描述中的變動，類型名稱已變更為 `Mutation`，而名稱為 `createPost`。管道組態已設定為我們的新變動函數 `add_func_2`。

------

為了摘要此範例中發生的情況， AWS AppSync 會自動將 欄位中定義的引數`createPost`從 GraphQL 結構描述轉換為 DynamoDB 操作。此範例使用 金鑰在 DynamoDB 中存放記錄`id`，該金鑰是使用我們的 `util.autoId()` 協助程式自動建立的。您從 AWS AppSync 主控台提出的請求或其他方式傳遞到內容引數 (`ctx.args.input`) 的所有其他欄位都會儲存為資料表的屬性。金鑰和屬性都會使用 `util.dynamodb.toMapValues(values)` 協助程式自動映射至相容的 DynamoDB 格式。

AWS AppSync 也支援用於編輯解析程式的測試和偵錯工作流程。您可以使用模擬`context`物件來查看範本的轉換值，然後再叫用它。或者，您可以在執行查詢時以互動方式檢視對資料來源的完整請求。如需詳細資訊，請參閱[測試和偵錯解析程式 (JavaScript)](https://docs.aws.amazon.com/appsync/latest/devguide/test-debug-resolvers-js.html) 和[監控和記錄](https://docs.aws.amazon.com/appsync/latest/devguide/monitoring.html#aws-appsync-monitoring)。

## 進階解析程式
<a name="advanced-resolvers-js"></a>

如果您遵循[設計結構描述](designing-your-schema.md#aws-appsync-designing-your-schema)中的選用分頁區段，您仍然需要將解析程式新增至您的請求，才能使用分頁。我們的範例使用稱為 的查詢分頁`getPosts`，一次只傳回請求的一部分物件。解析程式在該欄位上的程式碼可能如下所示：

```
/**
 * Performs a scan on the dynamodb data source
 */
export function request(ctx) {
  const { limit = 20, nextToken } = ctx.args;
  return { operation: 'Scan', limit, nextToken };
}

/**
 * @returns the result of the `put` operation
 */
export function response(ctx) {
  const { items: posts = [], nextToken } = ctx.result;
  return { posts, nextToken };
}
```

在請求中，我們會傳入請求的內容。我們的 `limit`是 *20*，這表示我們在第一個查詢`Posts`中傳回最多 20 個。我們的`nextToken`游標會固定為資料來源中的第一個`Post`項目。這些會傳遞給 args。然後，請求會執行從第一個`Post`到掃描限制數量的掃描。資料來源會將結果存放在內容中，該內容會傳遞給回應。回應會傳回`Posts`其擷取的 ，然後將 `nextToken` 設定為限制之後`Post`的項目。下一個請求會傳送到 以執行完全相同的物件，但在第一個查詢後立即從位移開始。請記住，這些類型的請求是依序完成的，而不是平行的。

# 測試和偵錯解析程式 in AWS AppSync (JavaScript)
<a name="test-debug-resolvers-js"></a>

AWS AppSync 會對資料來源在 GraphQL 欄位上執行解析程式。使用管道解析程式時， 函數會與您的資料來源互動。如 [JavaScript 解析程式概觀](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html)中所述， 函數會使用以 JavaScript 撰寫並在`APPSYNC_JS`執行時間執行的請求和回應處理常式，與資料來源通訊。這可讓您在與資料來源通訊之前和之後提供自訂邏輯和條件。

為了協助開發人員寫入、測試和偵錯這些解析程式， AWS AppSync 主控台也提供工具來建立 GraphQL 請求和回應，並將模擬資料縮減至個別欄位解析程式。此外，您可以在 AWS AppSync 主控台中執行查詢、變動和訂閱，並查看來自 Amazon CloudWatch 的整個請求的詳細日誌串流。這包括來自資料來源的結果。

## 使用模擬資料進行測試
<a name="testing-with-mock-data-js"></a>

叫用 GraphQL 解析程式時，會包含物件`context`，其中包含請求的相關資訊。其中包括用戶端引數、身分資訊，以及父 GraphQL 欄位的資料。它也會存放資料來源的結果，可用於回應處理常式。如需此結構和程式設計時要使用之可用協助程式公用程式的詳細資訊，請參閱[解析程式內容物件參考](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html)。

寫入或編輯解析程式函數時，您可以將*模擬*或*測試內容*物件傳遞至主控台編輯器。這可讓您查看請求和回應處理常式如何評估，而不會實際針對資料來源執行。例如您可傳送測試 `firstname: Shaggy` 引數，了解該引數在範本程式碼之中使用 `ctx.args.firstname` 時如何進行評估。您也可以測試任何公用程式協助程式的評估，例如 `util.autoId()` 或 `util.time.nowISO8601()`。

### 測試解析程式
<a name="test-a-resolver-js"></a>

此範例將使用 AWS AppSync 主控台來測試解析程式。

1. 登入 AWS 管理主控台 並開啟 [AppSync 主控台](https://console.aws.amazon.com/appsync/)。

   1. 在 **APIs儀表板**中，選擇您的 GraphQL API。

   1. 在 **Sidebar** 中，選擇**函數**。

1. 選擇現有的 函數。

1. 在**更新函數**頁面頂端，選擇**選取測試內容**，然後選擇**建立新內容**。

1. 選取範例內容物件，或在下面的**設定測試內容**視窗中手動填入 JSON。

1. 輸入**文字內容名稱**。

1. 選擇 **Save (儲存)** 按鈕。

1. 若要使用此項模擬的內容物件評估解析程式，選擇 **Run Test (執行測試)** 按鈕。

如需更實際的範例，假設您有一個應用程式存放的 GraphQL 類型`Dog`，該類型使用物件的自動 ID 產生，並將它們存放在 Amazon DynamoDB 中。您也想要從 GraphQL 變動的引數寫入一些值，並僅允許特定使用者查看回應。下列程式碼片段顯示結構描述的外觀：

```
type Dog {
  breed: String
  color: String
}

type Mutation {
  addDog(firstname: String, age: Int): Dog
}
```

您可以撰寫 an AWS AppSync 函數，並將其新增至您的`addDog`解析程式來處理變動。若要測試您的 AWS AppSync 函數，您可以填入內容物件，如下列範例所示。下列引數來自 `name` 及 `age`，以及將 `username` 填入 `identity` 物件之中的用戶端：

```
{
    "arguments" : {
        "firstname": "Shaggy",
        "age": 4
    },
    "source" : {},
    "result" : {
        "breed" : "Miniature Schnauzer",
        "color" : "black_grey"
    },
    "identity": {
        "sub" : "uuid",
        "issuer" : " https://cognito-idp.{region}.amazonaws.com/{userPoolId}",
        "username" : "Nadia",
        "claims" : { },
        "sourceIp" :[  "x.x.x.x" ],
        "defaultAuthStrategy" : "ALLOW"
    }
}
```

您可以使用下列程式碼測試您的 AWS AppSync 函數：

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

export function request(ctx) {
  return {
    operation: 'PutItem',
    key: util.dynamodb.toMapValues({ id: util.autoId() }),
    attributeValues: util.dynamodb.toMapValues(ctx.args),
  };
}

export function response(ctx) {
  if (ctx.identity.username === 'Nadia') {
    console.log("This request is allowed")
    return ctx.result;
  }
  util.unauthorized();
}
```

評估的請求和回應處理常式具有來自測試內容物件的資料，以及來自 產生的值`util.autoId()`。此外，若您將 `username` 變更為 `Nadia` 以外的值，將不會傳回結果，因為授權檢查將會失敗。如需精細存取控制的詳細資訊，請參閱[授權使用案例](security-authorization-use-cases.md#aws-appsync-security-authorization-use-cases)。

### 使用 AWS AppSync 的 APIs測試請求和回應處理常式
<a name="testing-with-appsync-api-js"></a>

您可以使用 `EvaluateCode` API 命令，以模擬資料遠端測試程式碼。若要開始使用 命令，請確定您已將 `appsync:evaluateMappingCode`許可新增至政策。例如：

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

****  

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

------

您可以使用 [AWS CLI](https://aws.amazon.com/cli/)或 [AWS SDKs](https://aws.amazon.com/tools/) 來利用 命令。例如，從上一節取得結構描述及其 AWS AppSync `Dog` 函數請求和回應處理常式。在本機工作站上使用 CLI，將程式碼儲存到名為 的檔案`code.js`，然後將`context`物件儲存到名為 的檔案`context.json`。從您的 shell 執行下列命令：

```
$ aws appsync evaluate-code \
  --code file://code.js \
  --function response \
  --context file://context.json \
  --runtime name=APPSYNC_JS,runtimeVersion=1.0.0
```

回應包含 ，`evaluationResult`其中包含處理常式傳回的承載。它還包含 物件，該`logs`物件會保留您的處理常式在評估期間產生的日誌清單。這可讓您輕鬆地偵錯程式碼執行，並查看評估的相關資訊，以協助故障診斷。例如：

```
{
    "evaluationResult": "{\"breed\":\"Miniature Schnauzer\",\"color\":\"black_grey\"}",
    "logs": [
        "INFO - code.js:13:5: \"This request is allowed\""
    ]
}
```

`evaluationResult` 可以剖析為 JSON，其提供：

```
{
  "breed": "Miniature Schnauzer",
  "color": "black_grey"
}
```

使用 SDK，您可以輕鬆整合來自您最愛測試套件的測試，以驗證處理常式的行為。我們建議您使用 [Jest 測試架構](https://jestjs.io/)建立測試，但任何測試套件都可以運作。下列程式碼片段顯示假設性驗證執行。請注意，我們預期評估回應是有效的 JSON，因此我們使用 從字串回應`JSON.parse`擷取 JSON：

```
const AWS = require('aws-sdk')
const fs = require('fs')
const client = new AWS.AppSync({ region: 'us-east-2' })
const runtime = {name:'APPSYNC_JS',runtimeVersion:'1.0.0')

test('request correctly calls DynamoDB', async () => {
  const code = fs.readFileSync('./code.js', 'utf8')
  const context = fs.readFileSync('./context.json', 'utf8')
  const contextJSON = JSON.parse(context)
  
  const response = await client.evaluateCode({ code, context, runtime, function: 'request' }).promise()
  const result = JSON.parse(response.evaluationResult)
  
  expect(result.key.id.S).toBeDefined()
  expect(result.attributeValues.firstname.S).toEqual(contextJSON.arguments.firstname)
})
```

 這會產生下列結果：

```
Ran all test suites.
> jest

PASS ./index.test.js
✓ request correctly calls DynamoDB (543 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 totalTime: 1.511 s, estimated 2 s
```

## 偵錯即時查詢
<a name="debugging-a-live-query-js"></a>

end-to-end測試和記錄無法用來偵錯生產應用程式。 AWS AppSync 可讓您使用 Amazon CloudWatch 記錄錯誤和完整請求詳細資訊。此外，您可以使用 AWS AppSync 主控台來測試 GraphQL 查詢、變動和訂閱，以及將每個請求的即時串流日誌資料傳回查詢編輯器以進行即時偵錯。針對訂閱，日誌會顯示連線時間資訊。

若要執行此操作，您需要事先啟用 Amazon CloudWatch logs，如[監控和記錄](monitoring.md#aws-appsync-monitoring)中所述。接著，在 AWS AppSync 主控台中，選擇**查詢**索引標籤，然後輸入有效的 GraphQL 查詢。在右下角區段中，按一下並拖曳**日誌**視窗以開啟日誌檢視。在頁面頂端，選擇執行箭頭圖示來執行您的 GraphQL 查詢。操作的完整請求和回應日誌會在幾分鐘後串流到本節，您可以在 主控台中檢視它們。

# 設定和使用管道解析程式 in AWS AppSync (JavaScript)
<a name="pipeline-resolvers-js"></a>

AWS AppSync 會在 GraphQL 欄位上執行解析程式。在某些情況下，應用程式需要執行多個操作，才能解析單一 GraphQL 欄位。透過管道解析程式，開發人員現在可以編寫稱為 Functions 的操作，並依序執行這些操作。在像是以需要先執行授權檢查才能擷取欄位資料的情況中，就很適合使用管道解析程式。

如需 JavaScript 管道解析程式架構的詳細資訊，請參閱 [JavaScript 解析程式概觀](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html#anatomy-of-a-pipeline-resolver-js)。

## 步驟 1：建立管道解析程式
<a name="create-a-pipeline-resolver-js"></a>

在 AWS AppSync 主控台中，前往**結構描述**頁面。

儲存下列結構描述：

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

type Mutation {
    signUp(input: Signup): User
}

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

input Signup {
    username: String!
    email: String!
}

type User {
    id: ID!
    username: String
    email: AWSEmail
}
```

我們將將管道解析程式連接到 **Mutation** 類型的 **signUp** 欄位。在右側的**變動**類型中，選擇`signUp`變動欄位旁的**連接**。將解析程式設定為 `pipeline resolver`和`APPSYNC_JS`執行時間，然後建立解析程式。

我們的管道解析程式會註冊使用者，此註冊的第一步是驗證電子郵件地址輸入，然後在系統中儲存此位使用者。我們將封裝 **validateEmail** 函數內的電子郵件驗證，以及在 **saveUser** 函數內儲存使用者。**validateEmail** 函數會先執行，而當電子郵件驗證有效時，**saveUser** 函數就會接著執行。

執行流程如下：

1. Mutation.signUp 解析程式請求處理常式

1. validateEmail 函數

1. saveUser 函數

1. Mutation.signUp 解析程式回應處理常式

由於我們可能會在 API 上的其他解析程式中重複使用 **validateEmail** 函數，因此我們希望避免存取 ，`ctx.args`因為這些函數會從一個 GraphQL 欄位變更為另一個欄位。反之，我們可以使用 `ctx.stash` 來存放 `signUp(input: Signup)` 輸入欄位引數所傳遞的電子郵件屬性。

取代您的請求和回應函數，以更新您的解析程式程式碼：

```
export function request(ctx) {
    ctx.stash.email = ctx.args.input.email
    return {};
}

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

選擇**建立**或**儲存**以更新解析程式。

## 步驟 2：建立 函數
<a name="create-a-function-js"></a>

在管道解析程式頁面的**函數**區段中，按一下**新增函數**，然後按一下**建立新函數**。您也可以在不經過解析程式頁面的情況下建立函數；若要這樣做，請在 AWS AppSync 主控台中前往**函數**頁面。選擇 **Create function (建立函數)** 按鈕。讓我們來建立可檢查電子郵件是否有效且來源是特定網域的函數。如果電子郵件無效，則該函數會引發錯誤。否則，它會轉送任何獲予的任何輸入。

請確定您已建立 **NONE** 類型的資料來源。在資料來源**名稱清單中選擇此資料來源**。針對**函數名稱**，在 中輸入 `validateEmail`。在**函數程式碼**區域中，使用此程式碼片段覆寫所有項目：

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

export function request(ctx) {
  const { email } = ctx.stash;
  const valid = util.matches(
    '^[a-zA-Z0-9_.+-]+@(?:(?:[a-zA-Z0-9-]+\.)?[a-zA-Z]+\.)?(myvaliddomain)\.com',
    email
  );
  if (!valid) {
    util.error(`"${email}" is not a valid email.`);
  }

  return { payload: { email } };
}

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

檢閱您的輸入，然後選擇**建立**。我們已建立我們 **validateEmail** 函數。重複這些步驟，使用下列程式碼建立 **saveUser** 函數 （為了簡單起見，我們使用 **NONE** 資料來源，並假裝使用者在函數執行後已儲存在系統中。)：

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

export function request(ctx) {
  return ctx.prev.result;
}

export function response(ctx) {
  ctx.result.id = util.autoId();
  return ctx.result;
}
```

我們剛建立了 **saveUser** 函數。

## 步驟 3：將函數新增至管道解析程式
<a name="adding-a-function-to-a-pipeline-resolver-js"></a>

我們的函數應該會自動新增至我們剛建立的管道解析程式。如果不是這種情況，或者您透過函數頁面建立**函數**，您可以按一下`signUp`解析程式頁面上的新增**函數**來連接函數。將 **validateEmail** 和 **saveUser** 函數新增至解析程式。**validateEmail** 函數應該放在 **saveUser** 函數之前。當您新增更多函數時，您可以使用**上下****移動**選項來重組函數的執行順序。檢閱您的變更，然後選擇**儲存**。

## 步驟 4：執行查詢
<a name="running-a-query-js"></a>

在 AWS AppSync 主控台中，前往**查詢**頁面。在瀏覽器中，請確定您使用的是變動。如果不是，請在下拉式清單`Mutation`中選擇 ，然後選擇 `+`。輸入下列查詢：

```
mutation {
  signUp(input: {email: "nadia@myvaliddomain.com", username: "nadia"}) {
    id
    username
  }
}
```

這應該會傳回如下內容：

```
{
  "data": {
    "signUp": {
      "id": "256b6cc2-4694-46f4-a55e-8cb14cc5d7fc",
      "username": "nadia"
    }
  }
}
```

我們已使用管道解析程式成功註冊我們的使用者，並完成輸入電子郵件的驗證。

# 建立基本查詢 (VTL)
<a name="configuring-resolvers"></a>

**注意**  
我們現在主要支援 APPSYNC\$1JS 執行期及其文件。請考慮[在此處](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers-js.html)使用 APPSYNC\$1JS 執行期及其指南。

GraphQL 解析程式將類型結構描述中的欄位連接到資料來源。解析程式是滿足請求的機制。 AWS AppSync 可以從結構描述自動建立和連接解析程式，或從現有資料表建立結構描述並連接解析程式，而無需撰寫任何程式碼。

Resolvers in AWS AppSync 使用 JavaScript 將 GraphQL 表達式轉換為資料來源可以使用的格式。或者，映射範本可以用 [Apache Velocity 範本語言 (VTL)](https://velocity.apache.org/engine/2.0/vtl-reference.html) 撰寫，將 GraphQL 表達式轉換為資料來源可以使用的格式。

本節將說明如何使用 VTL 設定解析程式。您可以在[解析程式映射範本程式設計指南中找到編寫解析程式的教學風格程式設計指南](resolver-mapping-template-reference-programming-guide.md#aws-appsync-resolver-mapping-template-reference-programming-guide)，以及可在[解析程式映射範本內容參考](resolver-context-reference.md#aws-appsync-resolver-mapping-template-context-reference)中找到程式設計時使用的協助程式公用程式。 AWS AppSync 也有內建測試和偵錯流程，可讓您從頭開始編輯或撰寫時使用。如需詳細資訊，請參閱[測試和偵錯解析程式](test-debug-resolvers.md#aws-appsync-test-debug-resolvers)。

我們建議您先遵循本指南，再嘗試使用任何上述教學課程。

在本節中，我們將逐步解說如何建立解析程式、為變動新增解析程式，以及使用進階組態。

## 建立您的第一個解析程式
<a name="create-your-first-resolver"></a>

遵循先前章節的範例，第一個步驟是為您的 `Query` 類型建立解析程式。

------
#### [ Console ]

1. 登入 AWS 管理主控台 並開啟 [AppSync 主控台](https://console.aws.amazon.com/appsync/)。

   1. 在 **APIs儀表板**中，選擇您的 GraphQL API。

   1. 在**側邊欄中**，選擇**結構描述**。

1. 在頁面右側，有一個稱為**解析程式**的視窗。此方塊包含頁面左側**結構描述**視窗中定義的類型和欄位清單。您可以將解析程式連接至欄位。例如，在**查詢**類型下，選擇 `getTodos` 欄位旁的**連接**。

1. 在**建立解析程式**頁面上，選擇您在[連接資料來源指南中建立的資料來源](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html)。在**設定映射範本**視窗中，您可以使用右側的下拉式清單選擇一般請求和回應映射範本，或自行撰寫。
**注意**  
將請求映射範本與回應映射範本配對稱為單位解析程式。單位解析程式通常用於執行輪換操作；我們建議僅將它們用於具有少量資料來源的單一操作。對於更複雜的操作，我們建議使用管道解析程式，其可以依序使用多個資料來源執行多個操作。  
如需請求與回應映射範本之間差異的詳細資訊，請參閱[單位解析程式](https://docs.aws.amazon.com//appsync/latest/devguide/resolver-mapping-template-reference-overview.html#unit-resolvers)。  
如需使用管道解析程式的詳細資訊，請參閱[管道解析程式](pipeline-resolvers.md#aws-appsync-pipeline-resolvers)。

1. 對於常見的使用案例， AWS AppSync 主控台具有內建範本，可用於從資料來源取得項目 （例如，所有項目查詢、個別查詢等）。例如，在設計`getTodos`沒有分頁的[結構](designing-your-schema.md#aws-appsync-designing-your-schema)描述的簡單版本上，列出項目的請求映射範本如下所示：

   ```
   {
       "version" : "2017-02-28",
       "operation" : "Scan"
   }
   ```

1. 您一律需要回應映射範本來隨附請求。主控台為清單提供具有下列傳遞值的預設值：

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

   在這個範例中，項目清單的 `context` 物件 (別名為 `$ctx`) 為 `$context.result.items` 格式。如果您的 GraphQL 操作傳回單一項目，則會是 `$context.result`。 AWS AppSync 提供常見操作的協助程式函數，例如先前列出的`$util.toJson`函數，以正確格式化回應。如需函數的完整清單，請參閱[解析程式映射範本公用程式參考](resolver-util-reference.md#aws-appsync-resolver-mapping-template-util-reference)。

1. 選擇**儲存解析程式**。

------
#### [ API ]

1. 呼叫 [https://docs.aws.amazon.com/appsync/latest/APIReference/API_CreateResolver.html](https://docs.aws.amazon.com/appsync/latest/APIReference/API_CreateResolver.html) API 來建立解析程式物件。

1. 您可以呼叫 [https://docs.aws.amazon.com/appsync/latest/APIReference/API_UpdateResolver.html](https://docs.aws.amazon.com/appsync/latest/APIReference/API_UpdateResolver.html) API 來修改解析程式的欄位。

------
#### [ CLI ]

1. 執行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html)命令來建立解析程式。

   您需要為此特定命令輸入 6 個參數：

   1. 您 API `api-id`的 。

   1. 您想要在結構描述中修改`type-name`的類型 。在主控台範例中，這是 `Query`。

   1. 您要在類型中修改的欄位`field-name`的 。在主控台範例中，這是 `getTodos`。

   1. 您在連接資料來源指南中建立`data-source-name`的資料來源的 。 [https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html)

   1. `request-mapping-template`，這是請求的內文。在主控台範例中，這是：

      ```
      {
          "version" : "2017-02-28",
          "operation" : "Scan"
      }
      ```

   1. `response-mapping-template`，這是回應的內文。在主控台範例中，這是：

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

   範例命令可能如下所示：

   ```
   aws appsync create-resolver --api-id abcdefghijklmnopqrstuvwxyz --type-name Query --field-name getTodos --data-source-name TodoTable --request-mapping-template "{ "version" : "2017-02-28", "operation" : "Scan", }" --response-mapping-template ""$"util.toJson("$"ctx.result.items)"
   ```

   輸出會在 CLI 中傳回。範例如下：

   ```
   {
       "resolver": {
           "kind": "UNIT",
           "dataSourceName": "TodoTable",
           "requestMappingTemplate": "{ version : 2017-02-28, operation : Scan, }",
           "resolverArn": "arn:aws:appsync:us-west-2:107289374856:apis/abcdefghijklmnopqrstuvwxyz/types/Query/resolvers/getTodos",
           "typeName": "Query",
           "fieldName": "getTodos",
           "responseMappingTemplate": "$util.toJson($ctx.result.items)"
       }
   }
   ```

1. 若要修改解析程式的欄位和/或映射範本，請執行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-resolver.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-resolver.html)命令。

   除了 `api-id` 參數之外，`create-resolver`命令中使用的參數會被`update-resolver`命令中的新值覆寫。

------

## 新增變動的解析程式
<a name="adding-a-resolver-for-mutations"></a>

下一個步驟是為您的 `Mutation` 類型建立解析程式。

------
#### [ Console ]

1. 登入 AWS 管理主控台 並開啟 [AppSync 主控台](https://console.aws.amazon.com/appsync/)。

   1. 在 **APIs儀表板**中，選擇您的 GraphQL API。

   1. 在**側邊欄中**，選擇**結構描述**。

1. 在**變動**類型下，選擇`addTodo`欄位旁的**連接**。

1. 在**建立解析程式**頁面上，選擇您在[連接資料來源指南中建立的資料來源](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html)。

1. 在**設定映射範本**視窗中，您將需要修改請求範本，因為這是您要將新項目新增至 DynamoDB 的變動。請使用下列要求映射範本：

   ```
   {
       "version" : "2017-02-28",
       "operation" : "PutItem",
       "key" : {
           "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id)
       },
       "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
   }
   ```

1. AWS AppSync 會自動將 `addTodo` 欄位中定義的引數從 GraphQL 結構描述轉換為 DynamoDB 操作。先前的範例使用 索引鍵將記錄存放在 DynamoDB 中`id`，該索引鍵會從變動引數傳遞為 `$ctx.args.id`。您傳遞的所有其他欄位都會使用 自動映射至 DynamoDB 屬性`$util.dynamodb.toMapValuesJson($ctx.args)`。

   在此解析程式中，使用下列的回應映射範本：

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

   AWS AppSync 也支援用於編輯解析程式的測試和偵錯工作流程。您可以使用模擬 `context` 物件，先查看範本轉換後的值，然後再叫用。或者，您可以在執行查詢時以互動方式檢視對資料來源的完整要求執行。如需詳細資訊，請參閱[測試和偵錯解析程式](test-debug-resolvers.md#aws-appsync-test-debug-resolvers)以及[監控和記錄](monitoring.md#aws-appsync-monitoring)。

1. 選擇**儲存解析程式**。

------
#### [ API ]

您也可以使用[建立第一個解析程式](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers.html#create-your-first-resolver)區段中的命令和本節中的參數詳細資訊，以 APIs 執行此操作。

------
#### [ CLI ]

您也可以使用[建立第一個解析程式](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers.html#create-your-first-resolver)區段中的命令和本節中的參數詳細資訊，在 CLI 中執行此操作。

------

此時，如果您未使用進階解析程式，您可以開始使用 GraphQL API，如[使用 API](using-your-api.md#aws-appsync-using-your-api) 中所述。

## 進階解析程式
<a name="advanced-resolvers"></a>

如果您遵循進階區段，並在[設計結構描述以執行分頁掃描中建置範例結構描述](designing-your-schema.md#aws-appsync-designing-your-schema)，請改用下列請求範本做為 `getTodos` 欄位：

```
{
    "version" : "2017-02-28",
    "operation" : "Scan",
    "limit": $util.defaultIfNull(${ctx.args.limit}, 20),
    "nextToken": $util.toJson($util.defaultIfNullOrBlank($ctx.args.nextToken, null))
}
```

對此分頁使用案例而言，回應映射不只是傳遞，因為其中必須包含*游標* (讓用戶端了解接下來從哪個頁面開始) 和結果集。映射範本如下所示：

```
{
    "todos": $util.toJson($context.result.items),
    "nextToken": $util.toJson($context.result.nextToken)
}
```

前述回應映射範本的欄位，應符合 `TodoConnection` 類型之中定義的欄位。

對於您擁有`Comments`資料表且正在解析`Todo`類型 （傳回 類型的`[Comment]`) 註解欄位的關係，您可以使用對第二個資料表執行查詢的映射範本。若要這樣做，您必須已經建立`Comments`資料表的資料來源，如[連接資料來源](attaching-a-data-source.md#aws-appsync-getting-started-build-a-schema-from-scratch)中所述。

**注意**  
我們針對第二個資料表使用查詢操作，僅供說明之用。您可以改為對 DynamoDB 使用其他操作。此外，您可以從其他資料來源提取資料，例如 AWS Lambda 或 Amazon OpenSearch Service，因為關係是由 GraphQL 結構描述控制。

------
#### [ Console ]

1. 登入 AWS 管理主控台 並開啟 [AppSync 主控台](https://console.aws.amazon.com/appsync/)。

   1. 在 **APIs儀表板**中，選擇您的 GraphQL API。

   1. 在**側邊欄中**，選擇**結構描述**。

1. 在**待辦事項**類型下，選擇`comments`欄位旁的**連接**。

1. 在**建立解析程式**頁面上，選擇您的**註解**資料表資料來源。快速入門指南中**註解**資料表的預設名稱為 `AppSyncCommentTable`，但可能會因您提供的名稱而有所不同。

1. 將下列程式碼片段新增至您的請求映射範本：

   ```
   {
       "version": "2017-02-28",
       "operation": "Query",
       "index": "todoid-index",
       "query": {
           "expression": "todoid = :todoid",
           "expressionValues": {
               ":todoid": {
                   "S": $util.toJson($context.source.id)
               }
           }
       }
   }
   ```

1. `context.source` 參照目前正在解析之欄位的父物件。在這個範例中，`source.id` 代表個別 `Todo` 物件，這個物件會在稍後用於查詢表達式。

   您可使用傳遞回應映射範本，如下所示：

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

1. 選擇**儲存解析程式**。

1. 最後，回到 主控台的**結構描述**頁面，將解析程式連接到 `addComment` 欄位，並指定`Comments`資料表的資料來源。在這種情況下，要求映射範本是簡單的 `PutItem`，其中具有註解為引數的特定 `todoid`，但您需要使用 `$utils.autoId()` 公用程式來為註解建立唯一的排序索引鍵，如下所示：

   ```
   {
       "version": "2017-02-28",
       "operation": "PutItem",
       "key": {
           "todoid": { "S": $util.toJson($context.arguments.todoid) },
           "commentid": { "S": "$util.autoId()" }
       },
       "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
   }
   ```

   使用傳遞回應範本，如下所示：

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

------
#### [ API ]

您也可以使用[建立第一個解析程式](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers.html#create-your-first-resolver)區段中的命令和本節中的參數詳細資訊，以 APIs 執行此操作。

------
#### [ CLI ]

您也可以使用[建立第一個解析程式](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers.html#create-your-first-resolver)區段中的命令和本節中的參數詳細資訊，在 CLI 中執行此操作。

------

# 使用直接 Lambda 解析程式 (VTL) 停用 VTL 映射範本
<a name="direct-lambda-reference"></a>

**注意**  
我們現在主要支援 APPSYNC\$1JS 執行期及其文件。請考慮[在此處](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers-js.html)使用 APPSYNC\$1JS 執行期及其指南。

使用直接 Lambda 解析程式時，您可以避免使用 VTL 映射範本 AWS Lambda 。 AWS AppSync 可以為您的 Lambda 函數提供預設承載，以及從 Lambda 函數對 GraphQL 類型的回應進行預設轉譯。您可以選擇提供請求範本、回應範本，或由 and AWS AppSync 處理。

若要進一步了解 AWS AppSync 提供的預設請求承載和回應轉譯，請參閱 [Direct Lambda 解析程式參考](resolver-mapping-template-reference-lambda.md#direct-lambda-resolvers)。如需設定 AWS Lambda 資料來源和設定 IAM 信任政策的詳細資訊，請參閱[連接資料來源](attaching-a-data-source.md)。

## 設定直接 Lambda 解析程式
<a name="direct-lambda-reference-resolvers"></a>

以下各節將說明如何連接 Lambda 資料來源，並將 Lambda 解析程式新增至您的欄位。

### 新增 Lambda 資料來源
<a name="direct-lambda-datasource"></a>

您必須先新增 Lambda 資料來源，才能啟用直接 Lambda 解析程式。

------
#### [ Console ]

1. 登入 AWS 管理主控台 並開啟 [AppSync 主控台](https://console.aws.amazon.com/appsync/)。

   1. 在 **APIs儀表板**中，選擇您的 GraphQL API。

   1. 在**側邊欄中**，選擇**資料來源**。

1. 選擇 **Create data source (建立資料來源)**。

   1. 針對**資料來源名稱**，輸入資料來源的名稱，例如 **myFunction**。

   1. 針對**資料來源類型**，選擇 **AWS Lambda 函數**。

   1. 針對**區域**，選擇適當的區域。

   1. 對於**函數 ARN**，從下拉式清單中選擇 Lambda 函數。您可以搜尋函數名稱，或手動輸入您要使用的函數 ARN。

   1. 建立新的 IAM 角色 （建議） 或選擇具有 IAM `lambda:invokeFunction` 許可的現有角色。現有角色需要信任政策，如[連接資料來源](attaching-a-data-source.md)一節所述。

      以下是 IAM 政策範例，其具有對資源執行操作所需的許可：

------
#### [ 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. 選擇**建立**按鈕。

------
#### [ CLI ]

1. 執行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-data-source.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-data-source.html)命令來建立資料來源物件。

   您需要為此特定命令輸入 4 個參數：

   1. 您 API `api-id`的 。

   1. 資料來源`name`的 。在主控台範例中，這是**資料來源名稱**。

   1. 資料來源`type`的 。在主控台範例中，這是 **AWS Lambda 函數**。

   1. `lambda-config`，這是主控台範例中的**函數 ARN**。
**注意**  
還有其他參數，例如 必須設定 `Region` ，但通常會預設為您的 CLI 組態值。

   範例命令可能如下所示：

   ```
   aws appsync create-data-source --api-id abcdefghijklmnopqrstuvwxyz --name myFunction --type AWS_LAMBDA --lambda-config lambdaFunctionArn=arn:aws:lambda:us-west-2:102847592837:function:appsync-lambda-example
   ```

   輸出會在 CLI 中傳回。範例如下：

   ```
   {
       "dataSource": {
           "dataSourceArn": "arn:aws:appsync:us-west-2:102847592837:apis/abcdefghijklmnopqrstuvwxyz/datasources/myFunction",
           "type": "AWS_LAMBDA",
           "name": "myFunction",
           "lambdaConfig": {
               "lambdaFunctionArn": "arn:aws:lambda:us-west-2:102847592837:function:appsync-lambda-example"
           }
       }
   }
   ```

1. 若要修改資料來源的屬性，請執行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-data-source.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/update-data-source.html)命令。

   除了 `api-id` 參數之外，`create-data-source`命令中使用的參數將由`update-data-source`命令中的新值覆寫。

------

### 啟用直接 Lambda 解析程式
<a name="direct-lambda-enable-templates"></a>

建立 Lambda 資料來源並設定適當的 IAM 角色以允許 AWS AppSync 叫用函數後，您可以將其連結至解析程式或管道函數。

------
#### [ Console ]

1. 登入 AWS 管理主控台 並開啟 [AppSync 主控台](https://console.aws.amazon.com/appsync/)。

   1. 在 **APIs儀表板**中，選擇您的 GraphQL API。

   1. 在**側邊欄中**，選擇**結構描述**。

1. 在**解析程式**視窗中，選擇欄位或操作，然後選取**連接**按鈕。

1. 在**建立新的解析程式**頁面中，從下拉式清單中選擇 Lambda 函數。

1. 為了利用直接 Lambda 解析程式，請確認在**設定映射範本區段中已停用請求和回應映射範本**。

1. 選擇**儲存解析程式**按鈕。

------
#### [ CLI ]
+ 執行 [https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/create-resolver.html)命令來建立解析程式。

  您需要為此特定命令輸入 6 個參數：

  1. 您 API `api-id`的 。

  1. 結構描述中 `type-name` 類型的 。

  1. 結構描述中 欄位`field-name`的 。

  1. `data-source-name`或您的 Lambda 函數名稱。

  1. `request-mapping-template`，這是請求的內文。在主控台範例中，已停用：

     ```
     " "
     ```

  1. `response-mapping-template`，這是回應的內文。在主控台範例中，這也已停用：

     ```
     " "
     ```

  範例命令可能如下所示：

  ```
  aws appsync create-resolver --api-id abcdefghijklmnopqrstuvwxyz --type-name Subscription --field-name onCreateTodo --data-source-name LambdaTest --request-mapping-template " " --response-mapping-template " "
  ```

  輸出會在 CLI 中傳回。範例如下：

  ```
  {
      "resolver": {
          "resolverArn": "arn:aws:appsync:us-west-2:102847592837:apis/abcdefghijklmnopqrstuvwxyz/types/Subscription/resolvers/onCreateTodo",
          "typeName": "Subscription",
          "kind": "UNIT",
          "fieldName": "onCreateTodo",
          "dataSourceName": "LambdaTest"
      }
  }
  ```

------

當您停用映射範本時，會在 中發生幾個額外的行為 AWS AppSync：
+ 透過停用映射範本，您要向 發出訊號 AWS AppSync ，表示您接受 [Direct Lambda 解析程式參考](resolver-mapping-template-reference-lambda.md#direct-lambda-resolvers)中指定的預設資料轉譯。
+ 透過停用請求映射範本，您的 Lambda 資料來源將收到包含整個[內容](resolver-context-reference.md)物件的承載。
+ 透過停用回應映射範本，您的 Lambda 調用結果將根據請求映射範本的版本或請求映射範本是否也停用而翻譯。

# 測試和偵錯解析程式 in AWS AppSync (VTL)
<a name="test-debug-resolvers"></a>

**注意**  
我們現在主要支援 APPSYNC\$1JS 執行期及其文件。請考慮[在此處](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers-js.html)使用 APPSYNC\$1JS 執行期及其指南。

AWS AppSync 會對資料來源在 GraphQL 欄位上執行解析程式。如[解析程式映射範本概觀](resolver-mapping-template-reference-overview.md#aws-appsync-resolver-mapping-template-reference-overview)中所述，解析程式會使用範本語言與資料來源通訊。這可讓您自訂行為，並在與資料來源通訊前後套用邏輯和條件。如需撰寫解析程式的教學風格程式設計指南簡介，請參閱[解析程式映射範本程式設計指南](resolver-mapping-template-reference-programming-guide.md#aws-appsync-resolver-mapping-template-reference-programming-guide)。

為了協助開發人員寫入、測試和偵錯這些解析程式， AWS AppSync 主控台也提供工具來建立 GraphQL 請求和回應，並將模擬資料縮減至個別欄位解析程式。此外，您可以在 AWS AppSync 主控台中執行查詢、變動和訂閱，並從 Amazon CloudWatch 查看整個請求的詳細日誌串流。其中包括資料來源的結果。

## 使用模擬資料進行測試
<a name="testing-with-mock-data"></a>

叫用 GraphQL 解析程式時，會包含包含請求相關資訊的`context`物件。其中包括用戶端引數、身分資訊，以及父 GraphQL 欄位的資料。它還包含來自資料來源的結果，可用於回應範本。如需詳細資訊來了解此項架構，以及程式設計時可用的各種協助公用程式，請參閱[解析程式映射範本內容參考](resolver-context-reference.md#aws-appsync-resolver-mapping-template-context-reference)。

寫入或編輯解析程式時，您可以將*模擬*或*測試內容*物件傳遞至主控台編輯器。這可讓您在沒有實際依據資料來源執行的情況下，了解這兩者如何請求及回應範本評估。例如您可傳送測試 `firstname: Shaggy` 引數，了解該引數在範本程式碼之中使用 `$ctx.args.firstname` 時如何進行評估。您也可以測試任何公用程式協助程式的評估，例如 `$util.autoId()` 或 `util.time.nowISO8601()`。

### 測試解析程式
<a name="test-a-resolver"></a>

此範例將使用 AWS AppSync 主控台來測試解析程式。

1. 登入 AWS 管理主控台 並開啟 [AppSync 主控台](https://console.aws.amazon.com/appsync/)。

   1. 在 **APIs儀表板**中，選擇您的 GraphQL API。

   1. 在**側邊欄中**，選擇**結構描述**。

1. 如果您尚未這麼做，請在 類型下和 欄位旁，選擇**連接**以新增您的解析程式。

   如需如何建置完整解析程式的詳細資訊，請參閱[設定解析程式](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers.html)。

   否則，請選取已在 欄位中的解析程式。

1. 在**編輯解析程式**頁面頂端，選擇**選取測試內容**，然後選擇**建立新內容**。

1. 選取範例內容物件，或在下方的**執行內容**視窗中手動填入 JSON。

1. 在**文字內容名稱**中輸入 。

1. 選擇 **Save (儲存)** 按鈕。

1. 在**編輯解析程式**頁面頂端，選擇**執行測試**。

如需更實際的範例，假設您有一個應用程式存放的 GraphQL 類型`Dog`，該類型使用物件的自動 ID 產生，並將它們存放在 Amazon DynamoDB 中。您也希望寫入 GraphQL 變動引數的值，並且只讓特定使用者看見回應。結構描述看起來類似如下：

```
type Dog {
  breed: String
  color: String
}

type Mutation {
  addDog(firstname: String, age: Int): Dog
}
```

當您為`addDog`變動新增解析程式時，您可以填入內容物件，如下列範例所示。下列引數來自 `name` 及 `age`，以及將 `username` 填入 `identity` 物件之中的用戶端：

```
{
    "arguments" : {
        "firstname": "Shaggy",
        "age": 4
    },
    "source" : {},
    "result" : {
        "breed" : "Miniature Schnauzer",
        "color" : "black_grey"
    },
    "identity": {
        "sub" : "uuid",
        "issuer" : " https://cognito-idp.{region}.amazonaws.com/{userPoolId}",
        "username" : "Nadia",
        "claims" : { },
        "sourceIp" :[  "x.x.x.x" ],
        "defaultAuthStrategy" : "ALLOW"
    }
}
```

您可利用下列要求及回應映射範本對此進行測試：

 **請求範本** 

```
{
    "version" : "2017-02-28",
    "operation" : "PutItem",
    "key" : {
        "id" : { "S" : "$util.autoId()" }
    },
    "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
}
```

 **回應範本** 

```
#if ($context.identity.username == "Nadia")
  $util.toJson($ctx.result)
#else
  $util.unauthorized()
#end
```

經過評估的範本擁有測試內容物件的資料，以及 `$util.autoId()` 產生的值。此外，若您將 `username` 變更為 `Nadia` 以外的值，將不會傳回結果，因為授權檢查將會失敗。如需精細存取控制的詳細資訊，請參閱[授權使用案例](security-authorization-use-cases.md#aws-appsync-security-authorization-use-cases)。

### 使用 AWS AppSync 的 APIs測試映射範本
<a name="testing-with-appsync-api"></a>

您可以使用 `EvaluateMappingTemplate` API 命令，以模擬資料遠端測試映射範本。若要開始使用 命令，請確定您已將 `appsync:evaluateMappingTemplate`許可新增至政策。例如：

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

****  

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

------

您可以使用 [AWS CLI](https://aws.amazon.com/cli/)或 [AWS SDKs](https://aws.amazon.com/tools/) 來利用 命令。例如，從上一節取得`Dog`結構描述及其請求/回應映射範本。在本機工作站上使用 CLI，將請求範本儲存到名為 的檔案`request.vtl`，然後將`context`物件儲存到名為 的檔案`context.json`。從您的 shell 執行下列命令：

```
aws appsync evaluate-mapping-template --template file://request.vtl --context file://context.json
```

該命令會傳回下列回應：

```
{
  "evaluationResult": "{\n    \"version\" : \"2017-02-28\",\n    \"operation\" : \"PutItem\",\n    \"key\" : {\n        \"id\" : { \"S\" : \"afcb4c85-49f8-40de-8f2b-248949176456\" }\n    },\n    \"attributeValues\" : {\"firstname\":{\"S\":\"Shaggy\"},\"age\":{\"N\":4}}\n}\n"
}
```

`evaluationResult` 包含使用提供的 測試您提供的範本的結果`context`。您也可以使用 AWS SDKs測試範本。以下是使用適用於 JavaScript V2 的 AWS SDK 的範例：

```
const AWS = require('aws-sdk')
const client = new AWS.AppSync({ region: 'us-east-2' })

const template = fs.readFileSync('./request.vtl', 'utf8')
const context = fs.readFileSync('./context.json', 'utf8')

client
  .evaluateMappingTemplate({ template, context })
  .promise()
  .then((data) => console.log(data))
```

使用 SDK，您可以輕鬆整合來自您最愛測試套件的測試，以驗證範本的行為。我們建議您使用 [Jest 測試架構](https://jestjs.io/)建立測試，但任何測試套件都可以運作。下列程式碼片段顯示假設性驗證執行。請注意，我們預期評估回應是有效的 JSON，因此我們使用 從字串回應`JSON.parse`擷取 JSON：

```
const AWS = require('aws-sdk')
const fs = require('fs')
const client = new AWS.AppSync({ region: 'us-east-2' })

test('request correctly calls DynamoDB', async () => {
  const template = fs.readFileSync('./request.vtl', 'utf8')
  const context = fs.readFileSync('./context.json', 'utf8')
  const contextJSON = JSON.parse(context)
  
  const response = await client.evaluateMappingTemplate({ template, context }).promise()
  const result = JSON.parse(response.evaluationResult)
  
  expect(result.key.id.S).toBeDefined()
  expect(result.attributeValues.firstname.S).toEqual(contextJSON.arguments.firstname)
})
```

 這會產生下列結果：

```
Ran all test suites.
> jest

PASS ./index.test.js
✓ request correctly calls DynamoDB (543 ms)

Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 1.511 s, estimated 2 s
```

## 偵錯即時查詢
<a name="debugging-a-live-query"></a>

end-to-end測試和記錄無法用來偵錯生產應用程式。 AWS AppSync 可讓您使用 Amazon CloudWatch 記錄錯誤和完整請求詳細資訊。此外，您可以使用 AWS AppSync 主控台來測試 GraphQL 查詢、變動和訂閱，以及將每個請求的即時串流日誌資料傳回查詢編輯器以進行即時偵錯。針對訂閱，日誌會顯示連線時間資訊。

若要執行此操作，您需要事先啟用 Amazon CloudWatch logs，如[監控和記錄](monitoring.md#aws-appsync-monitoring)中所述。接著，在 AWS AppSync 主控台中，選擇**查詢**索引標籤，然後輸入有效的 GraphQL 查詢。在右下角區段中，按一下並拖曳**日誌**視窗以開啟日誌檢視。在頁面頂端，選擇執行箭頭圖示來執行您的 GraphQL 查詢。幾分鐘後，操作的完整請求及回應日誌，將串流至此區段，然後您可在主控台中檢視。

# 設定和使用管道解析程式 in AWS AppSync (VTL)
<a name="pipeline-resolvers"></a>

**注意**  
我們現在主要支援 APPSYNC\$1JS 執行期及其文件。請考慮[在此處](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers-js.html)使用 APPSYNC\$1JS 執行期及其指南。

AWS AppSync 會在 GraphQL 欄位上執行解析程式。在某些情況下，應用程式需要執行多個操作，才能解析單一 GraphQL 欄位。透過管道解析程式，開發人員現在可以編寫稱為 Functions 的操作，並依序執行這些操作。在像是以需要先執行授權檢查才能擷取欄位資料的情況中，就很適合使用管道解析程式。

管道解析程式包含 **Before** 映射範本和 **After** 映射範本，以及一份函數清單。每個函數都有一個**請求**和**回應**映射範本，它會針對資料來源執行。由於管道解析程式是將執行委派到一份函數清單，所以不會連結到任何資料來源。單位解析程式和函數是對資料來源執行操作的基礎。如需詳細資訊，請參閱[解析程式映射範本概觀](resolver-mapping-template-reference-overview.md#aws-appsync-resolver-mapping-template-reference-overview)。

## 步驟 1：建立管道解析程式
<a name="create-a-pipeline-resolver"></a>

在 AWS AppSync 主控台中，前往**結構描述**頁面。

儲存下列結構描述：

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

type Mutation {
    signUp(input: Signup): User
}

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

input Signup {
    username: String!
    email: String!
}

type User {
    id: ID!
    username: String
    email: AWSEmail
}
```

我們將將管道解析程式連接到 **Mutation** 類型的 **signUp** 欄位。在右側的**變動**類型中，選擇`signUp`變動欄位旁的**連接**。在建立解析程式頁面上，按一下**動作**，然後按一下**更新執行時間**。選擇 `Pipeline Resolver`，然後選擇 `VTL`，然後選擇**更新**。頁面現在應會顯示三個區段：**映射前範本**文字區域、**函數**區段，以及**映射後範本**文字區域。

我們的管道解析程式會註冊使用者，此註冊的第一步是驗證電子郵件地址輸入，然後在系統中儲存此位使用者。我們將在 **validateEmail** 函數中封裝該電子郵件驗證，並在 **saveUser** 函數中封裝使用者儲存步驟。**validateEmail** 函數會先執行，而當電子郵件驗證有效時，**saveUser** 函數就會接著執行。

執行流程將如下所示：

1. Mutation.signUp 解析程式要求映射範本

1. validateEmail 函數

1. saveUser 函數

1. Mutation.signUp 解析程式回應映射範本

由於我們可能會在 API 上的其他解析程式中重複使用 **validateEmail** 函數，因此我們希望避免存取 ，`$ctx.args`因為這些函數會從一個 GraphQL 欄位變更為另一個欄位。反之，我們可以使用 `$ctx.stash` 來存放 `signUp(input: Signup)` 輸入欄位引數所傳遞的電子郵件屬性。

映射範本**之前**：

```
## store email input field into a generic email key
$util.qr($ctx.stash.put("email", $ctx.args.input.email))
{}
```

主控台提供預設的 **AFTER** 映射範本，我們將使用：

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

選擇**建立**或**儲存**以更新解析程式。

## 步驟 2：建立 函數
<a name="create-a-function"></a>

在管道解析程式頁面的**函數**區段中，按一下**新增函數**，然後按一下**建立新函數**。您也可以在不經過解析程式頁面的情況下建立函數；若要這樣做，請在 AWS AppSync 主控台中前往**函數**頁面。選擇 **Create function (建立函數)** 按鈕。讓我們來建立可檢查電子郵件是否有效且來源是特定網域的函數。如果電子郵件無效，則該函數會引發錯誤。否則，它會轉送任何獲予的任何輸入。

在新函數頁面上，選擇**動作**，然後選擇**更新執行時間**。選擇 `VTL`，然後選擇**更新**。請確定您已建立 **NONE** 類型的資料來源。在資料來源**名稱清單中選擇此資料來源**。在**函數名稱**中輸入 `validateEmail`。在**函數程式碼**區域中，使用此程式碼片段覆寫所有項目：

```
#set($valid = $util.matches("^[a-zA-Z0-9_.+-]+@(?:(?:[a-zA-Z0-9-]+\.)?[a-zA-Z]+\.)?(myvaliddomain)\.com", $ctx.stash.email))
#if (!$valid)
    $util.error("$ctx.stash.email is not a valid email.")
#end
{
    "payload": { "email": $util.toJson(${ctx.stash.email}) }
}
```

將此貼到回應映射範本中：

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

檢閱您的變更，然後選擇**建立**。我們已建立我們 **validateEmail** 函數。重複這些步驟，使用下列請求和回應映射範本建立 **saveUser** 函數 （為了簡單起見，我們使用 **NONE** 資料來源，並在函數執行後假設使用者已儲存在系統中。)：

要求映射範本：

```
## $ctx.prev.result contains the signup input values. We could have also
## used $ctx.args.input.
{
    "payload": $util.toJson($ctx.prev.result)
}
```

回應映射範本：

```
## an id is required so let's add a unique random identifier to the output
$util.qr($ctx.result.put("id", $util.autoId()))
$util.toJson($ctx.result)
```

我們剛建立了 **saveUser** 函數。

## 步驟 3：將函數新增至管道解析程式
<a name="adding-a-function-to-a-pipeline-resolver"></a>

我們的函數應該會自動新增至我們剛建立的管道解析程式。如果不是這種情況，或者您透過函數頁面建立**函數**，您可以在解析程式頁面上按一下**新增函數**來連接它們。將 **validateEmail** 和 **saveUser** 函數新增至解析程式。**validateEmail** 函數應該放在 **saveUser** 函數之前。當您新增更多函數時，您可以使用**上下****移動**選項來重組函數的執行順序。檢閱您的變更，然後選擇**儲存**。

## 步驟 4：執行查詢
<a name="executing-a-query"></a>

在 AWS AppSync 主控台中，前往**查詢**頁面。在瀏覽器中，請確定您使用的是變動。如果不是，請在下拉式清單`Mutation`中選擇 ，然後選擇 `+`。輸入下列查詢：

```
mutation {
  signUp(input: {
    email: "nadia@myvaliddomain.com"
    username: "nadia"
  }) {
    id
    email
  }
}
```

這應該會傳回如下內容：

```
{
  "data": {
    "signUp": {
      "id": "256b6cc2-4694-46f4-a55e-8cb14cc5d7fc",
      "email": "nadia@myvaliddomain.com"
    }
  }
}
```

我們已使用管道解析程式成功註冊我們的使用者，並完成輸入電子郵件的驗證。若要取得更多著重管道解析程式的全面教學課程，您可以移至[教學課程：管道解析程式](tutorial-pipeline-resolvers.md#aws-appsync-tutorial-pipeline-resolvers) 

# 搭配 AWS CDK 使用 AWS AppSync API
<a name="using-your-api"></a>

**提示**  
在使用 CDK 之前，我們建議您檢閱 CDK 的[官方文件](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html)以及 CDK AWS AppSync參考。 [https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_appsync-readme.html)  
我們也建議確保您的 [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) 和 [NPM](https://docs.npmjs.com/) 安裝可在您的系統上運作。

在本節中，我們將建立簡單的 CDK 應用程式，可從 DynamoDB 資料表新增和擷取項目。這是使用[設計結構描述](https://docs.aws.amazon.com/appsync/latest/devguide/designing-your-schema.html)、[連接資料來源](https://docs.aws.amazon.com/appsync/latest/devguide/attaching-a-data-source.html)和[設定解析程式 (JavaScript)](https://docs.aws.amazon.com/appsync/latest/devguide/configuring-resolvers-js.html) 區段中的一些程式碼的快速入門範例。

## 設定 CDK 專案
<a name="Setting-up-a-cdk-project"></a>

**警告**  
視您的環境而定，這些步驟可能不完全準確。我們假設您的系統已安裝必要的公用程式、與服務的界面方式 AWS ，以及適當的組態。

第一步是安裝 AWS CDK。在 CLI 中，您可以輸入下列命令：

```
npm install -g aws-cdk
```

接著，您需要建立專案目錄，然後導覽至它。建立和導覽至目錄的一組命令範例如下：

```
mkdir example-cdk-app
cd example-cdk-app
```

接著，您需要建立應用程式。我們的服務主要使用 TypeScript。在您的專案目錄中，輸入下列命令：

```
cdk init app --language typescript
```

當您執行此操作時，將會安裝 CDK 應用程式及其初始化檔案：

![\[Terminal output showing Git repository initialization and npm install completion.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-init-app-example.png)


您的專案結構可能如下所示：

![\[Project directory structure showing folders and files for an example CDK app.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-init-directories.png)


您會注意到我們有幾個重要的目錄：
+ `bin`：初始 bin 檔案將建立應用程式。我們不會在本指南中碰觸到此項目。
+ `lib`：lib 目錄包含您的堆疊檔案。您可以將堆疊檔案視為個別的執行單位。建構將位於我們的堆疊檔案內。基本上，這些是服務的資源，會在應用程式部署 CloudFormation 時在其中啟動。這就是我們大部分編碼都會發生的地方。
+ `node_modules`：此目錄是由 NPM 建立，並包含您使用 `npm`命令安裝的所有套件相依性。

我們的初始堆疊檔案可能包含如下內容：

```
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
// import * as sqs from 'aws-cdk-lib/aws-sqs';

export class ExampleCdkAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // The code that defines your stack goes here

    // example resource
    // const queue = new sqs.Queue(this, 'ExampleCdkAppQueue', {
    //   visibilityTimeout: cdk.Duration.seconds(300)
    // });
  }
}
```

這是在我們的應用程式中建立堆疊的樣板程式碼。我們在此範例中的大部分程式碼都會進入此類別的範圍內。

若要驗證您的堆疊檔案是否在應用程式中，請在應用程式的 目錄中，在終端機中執行下列命令：

```
cdk ls
```

應該會出現堆疊的清單。如果沒有，則您可能需要再次執行這些步驟，或查看官方文件以取得協助。

如果您想要在部署之前建置程式碼變更，您可以隨時在終端機中執行下列命令：

```
npm run build
```

此外，若要在部署之前查看變更：

```
cdk diff
```

將程式碼新增至堆疊檔案之前，我們會執行引導。引導允許我們在應用程式部署之前佈建 CDK 的資源。如需此程序的詳細資訊，請參閱[此處](https://docs.aws.amazon.com/cdk/v2/guide/bootstrapping.html)。若要建立引導，命令為：

```
cdk bootstrap aws://ACCOUNT-NUMBER/REGION
```

**提示**  
此步驟需要您帳戶中的數個 IAM 許可。如果您沒有引導，您的引導將被拒絕。如果發生這種情況，您可能需要刪除由引導造成的不完整資源，例如它產生的 S3 儲存貯體。

Bootstrap 將啟動數個資源。最終訊息會如下所示：

![\[Terminal output showing successful bootstrapping of an AWS environment.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-init-bootstrap-final.png)


每個區域每個帳戶會執行一次此操作，因此您不需要經常執行此操作。引導的主要資源是 CloudFormation 堆疊和 Amazon S3 儲存貯體。

Amazon S3 儲存貯體用於存放授予執行部署所需許可的檔案和 IAM 角色。所需的資源是在 CloudFormation 堆疊中定義，稱為引導堆疊，通常命名為 `CDKToolkit`。與任何 CloudFormation 堆疊一樣，它在部署之後會出現在 CloudFormation 主控台中：

![\[CDKToolkit stack with CREATE_COMPLETE status in CloudFormation console.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-init-bootstrap-cfn-console.png)


您可以針對儲存貯體說出相同的 ：

![\[S3 bucket details showing name, region, access settings, and creation date.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-init-bootstrap-bucket-console.png)


若要匯入堆疊檔案中所需的服務，我們可以使用下列命令：

```
npm install aws-cdk-lib # V2 command
```

**提示**  
如果 V2 發生問題，您可以使用 V1 命令安裝個別程式庫：  

```
npm install @aws-cdk/aws-appsync @aws-cdk/aws-dynamodb
```
我們不建議這麼做，因為 V1 已棄用。

## 實作 CDK 專案 - 結構描述
<a name="implementing-a-cdk-project-schema"></a>

我們現在可以開始實作程式碼。首先，我們必須建立結構描述。您可以直接在應用程式中建立`.graphql`檔案：

```
mkdir schema
touch schema.graphql
```

在我們的範例中，我們包含了一個名為 的頂層目錄，`schema`其中包含我們的 `schema.graphql`：

![\[File structure showing a schema folder containing schema.graphql file.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-code-schema-directory.png)


在我們的結構描述中，讓我們包含一個簡單的範例：

```
input CreatePostInput {
    title: String
    content: String
}

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

type Mutation {
    createPost(input: CreatePostInput!): Post
}

type Query {
    getPost: [Post]
}
```

回到堆疊檔案，我們需要確定已定義下列匯入指令：

```
import * as cdk from 'aws-cdk-lib';
import * as appsync from 'aws-cdk-lib/aws-appsync';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import { Construct } from 'constructs';
```

在 類別中，我們將新增程式碼來製作 GraphQL API，並將其連接到我們的`schema.graphql`檔案：

```
export class ExampleCdkAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    
    // makes a GraphQL API
    const api = new appsync.GraphqlApi(this, 'post-apis', {
      name: 'api-to-process-posts',
      schema: appsync.SchemaFile.fromAsset('schema/schema.graphql'),
    });
  }
}
```

我們也會新增一些程式碼來列印 GraphQL URL、API 金鑰和區域：

```
export class ExampleCdkAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    
    // Makes a GraphQL API construct
    const api = new appsync.GraphqlApi(this, 'post-apis', {
      name: 'api-to-process-posts',
      schema: appsync.SchemaFile.fromAsset('schema/schema.graphql'),
    });

    // Prints out URL
    new cdk.CfnOutput(this, "GraphQLAPIURL", {
      value: api.graphqlUrl
    });

    // Prints out the AppSync GraphQL API key to the terminal
    new cdk.CfnOutput(this, "GraphQLAPIKey", {
      value: api.apiKey || ''
    });

    // Prints out the stack region to the terminal
    new cdk.CfnOutput(this, "Stack Region", {
      value: this.region
    });
  }
}
```

此時，我們將再次使用部署應用程式：

```
cdk deploy
```

這是結果：

![\[Deployment output showing ExampleCdkAppStack details, including GraphQL API URL and stack region.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-code-deploy-schema.png)


顯示我們的範例成功，但讓我們檢查 AWS AppSync 主控台以確認：

![\[GraphQL interface showing successful API request with response data displayed.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-code-deploy-schema-result-1.png)


我們的 API 似乎已建立。現在，我們將檢查連接到 API 的結構描述：

![\[GraphQL schema defining CreatePostInput, Post type, Mutation, and Query operations.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-code-deploy-schema-result-2.png)


這似乎符合我們的結構描述程式碼，因此成功。從中繼資料觀點確認這一點的另一個方法是查看 CloudFormation 堆疊：

![\[CloudFormation stack showing ExampleCdkAppStack update complete and CDKToolkit creation complete.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-code-deploy-schema-result-3.png)


當我們部署 CDK 應用程式時，它會逐步 CloudFormation 啟動引導等資源。我們應用程式內的每個堆疊都會以 1：1 與 CloudFormation 堆疊映射。如果您返回堆疊程式碼，堆疊名稱會從類別名稱 中擷取`ExampleCdkAppStack`。您可以在 GraphQL API 建構中查看其建立的資源，這也符合我們的命名慣例：

![\[Expanded view of post-apis resource showing Schema, DefaultApiKey, and CDKMetadata.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-code-deploy-schema-result-4.png)


## 實作 CDK 專案 - 資料來源
<a name="implementing-a-cdk-project-data-source"></a>

接下來，我們需要新增資料來源。我們的範例將使用 DynamoDB 資料表。在堆疊類別中，我們會新增一些程式碼來建立新的資料表：

```
export class ExampleCdkAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Makes a GraphQL API construct
    const api = new appsync.GraphqlApi(this, 'post-apis', {
      name: 'api-to-process-posts',
      schema: appsync.SchemaFile.fromAsset('schema/schema.graphql'),
    });

    //creates a DDB table
    const add_ddb_table = new dynamodb.Table(this, 'posts-table', {
      partitionKey: {
        name: 'id',
        type: dynamodb.AttributeType.STRING,
      },
    });

    // Prints out URL
    new cdk.CfnOutput(this, "GraphQLAPIURL", {
      value: api.graphqlUrl
    });

    // Prints out the AppSync GraphQL API key to the terminal
    new cdk.CfnOutput(this, "GraphQLAPIKey", {
      value: api.apiKey || ''
    });

    // Prints out the stack region to the terminal
    new cdk.CfnOutput(this, "Stack Region", {
      value: this.region
    });
  }
}
```

此時，讓我們再次部署：

```
cdk deploy
```

我們應該檢查 DynamoDB 主控台是否有新的資料表：

![\[DynamoDB console showing ExampleCdkAppStack-poststable as Active with Provisioned capacity.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-code-deploy-ddb-result-1.png)


我們的堆疊名稱正確，且資料表名稱符合我們的程式碼。如果我們再次檢查 CloudFormation 堆疊，現在將會看到新的資料表：

![\[Expanded view of a logical ID in CloudFormation showing post-apis, posts-table, and CDKMetadata.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-code-deploy-ddb-result-2.png)


## 實作 CDK 專案 - Resolver
<a name="implementing-a-cdk-project-resolver"></a>

此範例將使用兩個解析程式：一個用於查詢資料表，另一個用於新增資料表。由於我們使用管道解析程式，因此我們需要宣告兩個管道解析程式，每個管道解析程式各有一個 函數。在查詢中，我們將新增下列程式碼：

```
export class ExampleCdkAppStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Makes a GraphQL API construct
    const api = new appsync.GraphqlApi(this, 'post-apis', {
      name: 'api-to-process-posts',
      schema: appsync.SchemaFile.fromAsset('schema/schema.graphql'),
    });

    //creates a DDB table
    const add_ddb_table = new dynamodb.Table(this, 'posts-table', {
      partitionKey: {
        name: 'id',
        type: dynamodb.AttributeType.STRING,
      },
    });

    // Creates a function for query
    const add_func = new appsync.AppsyncFunction(this, 'func-get-post', {
      name: 'get_posts_func_1',
      api,
      dataSource: api.addDynamoDbDataSource('table-for-posts', add_ddb_table),
      code: appsync.Code.fromInline(`
          export function request(ctx) {
          return { operation: 'Scan' };
          }

          export function response(ctx) {
          return ctx.result.items;
          }
  `),
      runtime: appsync.FunctionRuntime.JS_1_0_0,
    });

    // Creates a function for mutation
    const add_func_2 = new appsync.AppsyncFunction(this, 'func-add-post', {
      name: 'add_posts_func_1',
      api,
      dataSource: api.addDynamoDbDataSource('table-for-posts-2', add_ddb_table),
      code: appsync.Code.fromInline(`
          export function request(ctx) {
            return {
            operation: 'PutItem',
            key: util.dynamodb.toMapValues({id: util.autoId()}),
            attributeValues: util.dynamodb.toMapValues(ctx.args.input),
            };
          }

          export function response(ctx) {
            return ctx.result;
          }
      `),
      runtime: appsync.FunctionRuntime.JS_1_0_0,
    });

    // Adds a pipeline resolver with the get function
    new appsync.Resolver(this, 'pipeline-resolver-get-posts', {
      api,
      typeName: 'Query',
      fieldName: 'getPost',
      code: appsync.Code.fromInline(`
          export function request(ctx) {
          return {};
          }

          export function response(ctx) {
          return ctx.prev.result;
          }
  `),
      runtime: appsync.FunctionRuntime.JS_1_0_0,
      pipelineConfig: [add_func],
    });

    // Adds a pipeline resolver with the create function
    new appsync.Resolver(this, 'pipeline-resolver-create-posts', {
      api,
      typeName: 'Mutation',
      fieldName: 'createPost',
      code: appsync.Code.fromInline(`
          export function request(ctx) {
          return {};
          }

          export function response(ctx) {
          return ctx.prev.result;
          }
  `),
      runtime: appsync.FunctionRuntime.JS_1_0_0,
      pipelineConfig: [add_func_2],
    });

    // Prints out URL
    new cdk.CfnOutput(this, "GraphQLAPIURL", {
      value: api.graphqlUrl
    });

    // Prints out the AppSync GraphQL API key to the terminal
    new cdk.CfnOutput(this, "GraphQLAPIKey", {
      value: api.apiKey || ''
    });

    // Prints out the stack region to the terminal
    new cdk.CfnOutput(this, "Stack Region", {
      value: this.region
    });
  }
}
```

在此程式碼片段中，我們新增了名為 的管道解析程式，`pipeline-resolver-create-posts`並`func-add-post`附加了名為 的函數。這是將`Posts`新增至資料表的程式碼。另一個管道解析程式使用名為 `pipeline-resolver-get-posts`的函數呼叫`func-get-post`，該函數會擷取`Posts`新增至資料表的 。

我們將部署此項目以將其新增至 AWS AppSync 服務：

```
cdk deploy
```

讓我們檢查 AWS AppSync 主控台，看看它們是否已連接到我們的 GraphQL API：

![\[GraphQL API schema showing mutation and query fields with Pipeline resolvers.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-code-deploy-resolver-result-1.png)


它看起來是正確的。在程式碼中，這兩個解析程式都連接到我們製作的 GraphQL API （由解析程式和函數中存在的 props `api` 值表示）。在 GraphQL API 中，我們連接解析程式的欄位也在 props 中指定 （由每個解析程式中的 `typename`和 `fieldname` props 定義）。

讓我們看看解析程式的內容從 開始是否正確`pipeline-resolver-get-posts`：

![\[Code snippet showing request and response functions in a resolver, with an arrow pointing to them.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-code-deploy-resolver-result-2.png)


前後處理常式符合我們的`code`道具值。我們也可以看到名為 的函數`add_posts_func_1`，其符合我們在解析程式中附加的函數名稱。

讓我們看看該函數的程式碼內容：

![\[Function code showing request and response methods for a PutItem operation.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-code-deploy-resolver-result-3.png)


這符合`add_posts_func_1`函數的`code`道具。我們的查詢已成功上傳，因此我們檢查查詢：

![\[Resolver code with request and response functions, and a get_posts_func_1 function listed below.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-code-deploy-resolver-result-4.png)


這些也符合程式碼。如果我們查看 `get_posts_func_1`：

![\[Code snippet showing two exported functions: request returning 'Scan' operation and response returning items.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-code-deploy-resolver-result-5.png)


一切似乎都就位。為了從中繼資料的角度確認這一點，我們可以再次檢查 中的 CloudFormation 堆疊：

![\[List of logical IDs for AWS resources including API, table, functions, and pipelines.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-code-deploy-resolver-result-6.png)


現在，我們需要執行一些請求來測試此程式碼。

## 實作 CDK 專案 - 請求
<a name="implementing-a-cdk-project-requests"></a>

為了在 AWS AppSync 主控台測試我們的應用程式，我們提出了一個查詢和一個變動：

![\[GraphQL code snippet showing a query to get post details and a mutation to create a post.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-code-request-1.png)


`MyMutation` 包含具有引數 `1970-01-01T12:30:00.000Z`和 `createPost`的操作`first post`。它會傳回我們傳入`title`的 `date`和 ，以及自動產生的`id`值。執行變動會產生結果：

```
{
  "data": {
    "createPost": {
      "date": "1970-01-01T12:30:00.000Z",
      "id": "4dc1c2dd-0aa3-4055-9eca-7c140062ada2",
      "title": "first post"
    }
  }
}
```

如果我們快速檢查 DynamoDB 資料表，我們可以在掃描時在資料表中看到我們的項目：

![\[DynamoDB table entry showing id, date, and title fields for a single item.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cdk-code-request-2.png)


返回 AWS AppSync 主控台，如果我們執行查詢來擷取此 `Post`，我們會取得下列結果：

```
{
  "data": {
    "getPost": [
      {
        "id": "9f62c4dd-49d5-48d5-b835-143284c72fe0",
        "date": "1970-01-01T12:30:00.000Z",
        "title": "first post"
      }
    ]
  }
}
```

# 在 中使用即時資料應用程式的訂閱 AWS AppSync
<a name="aws-appsync-real-time-data"></a>

**重要**  
自 2025 年 3 月 13 日起，您可以使用 AWS AppSync Events 建置由 WebSockets 支援的即時 PubSub API。如需詳細資訊，請參閱《AppSync Events 開發人員指南》中的[透過 WebSocket 發佈](https://docs.aws.amazon.com/appsync/latest/eventapi/publish-websocket.html)事件。 *AWS AppSync *

AWS AppSync 可讓您利用訂閱來實作即時應用程式更新、推送通知等。當用戶端叫用 GraphQL 訂閱操作時， AWS AppSync 會自動建立和維護安全的 WebSocket 連線。應用程式接著可以即時將資料從資料來源分發給訂閱者，同時 AWS AppSync 會持續管理應用程式的連線和擴展需求。以下各節將向您展示 in AWS AppSync 訂閱的運作方式。

## GraphQL 結構描述訂閱指令
<a name="graphql-schema-subscription-directives"></a>

訂閱 in AWS AppSync 被調用為對變動的回應。這表示您可以在變動上指定 GraphQL 結構描述指令，讓任何資料來源 in AWS AppSync 即時。

 AWS Amplify 用戶端程式庫會自動處理訂閱連線管理。這些程式庫使用純 WebSockets 做為用戶端和服務之間的網路通訊協定。

**注意**  
若要控制訂閱的連線時間授權，您可以使用 AWS Identity and Access Management (IAM) AWS Lambda、Amazon Cognito 身分集區或 Amazon Cognito 使用者集區進行欄位層級授權。對於訂閱的精細存取控制，您可以將解析程式連接至訂閱欄位，並使用發起人身分和 AWS AppSync 資料來源執行邏輯。如需詳細資訊，請參閱[設定授權和身分驗證來保護 GraphQL APIs](security-authz.md)。

會從變動觸發訂閱且會將變動選擇設定傳送給訂閱者。

以下範例示範如何使用 GraphQL 訂閱。它不會指定資料來源，因為資料來源可以是 Lambda、Amazon DynamoDB 或 Amazon OpenSearch Service。

若要開始使用訂閱，您必須將訂閱進入點新增至您的結構描述，如下所示：

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

假設您有一個部落格文章網站，以及您想要訂閱新部落格和變更現有的部落格。若要執行此操作，請將以下 `Subscription` 定義新增至結構描述：

```
type Subscription {
    addedPost: Post
    updatedPost: Post
    deletedPost: 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!
}
```

您可以透過為您希望接收通知的每個訂閱新增 `@aws_subscribe(mutations: ["mutation_field_1", "mutation_field_2"])` 指示 (如下所示) 讓這些欄位變得即時：

```
type Subscription {
    addedPost: Post
    @aws_subscribe(mutations: ["addPost"])
    updatedPost: Post
    @aws_subscribe(mutations: ["updatePost"])
    deletedPost: Post
    @aws_subscribe(mutations: ["deletePost"])
}
```

由於 `@aws_subscribe(mutations: ["",..,""])`採用一系列的變動輸入，因此您可以指定多個變動來啟動訂閱。如果您是從用戶端進行訂閱，您的 GraphQL 查詢可能如下所示：

```
subscription NewPostSub {
    addedPost {
        __typename
        version
        title
        content
        author
        url
    }
}
```

用戶端連線和工具需要此訂閱查詢。

使用純 WebSockets 用戶端時，每個用戶端都會完成選取集篩選，因為每個用戶端都可以定義自己的選取集。在此情況下，訂閱選項集必須是變動選項集的子集。例如，連結至變動 `addPost(...){id author title url version}` 的訂閱 `addedPost{author title}` 僅接收文章的作者和標題。而沒有接收其他欄位。但是，如果變動缺少其選項集中的作者，則訂閱者將取得作者欄位的 `null` 值 (或者如果作者欄位在結構描述中被定義為必要/非 null，則會出現錯誤)。

使用純 WebSockets 時，訂閱選擇集至關重要。如果訂閱中未明確定義欄位，則 AWS AppSync 不會傳回 欄位。

在上述範例中，訂閱沒有引數。假設您的結構描述如下所示：

```
type Subscription {
    updatedPost(id:ID! author:String): Post
    @aws_subscribe(mutations: ["updatePost"])
}
```

在此情況下，您的用戶端定義訂閱如下：

```
subscription UpdatedPostSub {
    updatedPost(id:"XYZ", author:"ABC") {
        title
        content
    }
}
```

在結構描述 `subscription` 欄位的傳回類型必須與對應變動欄位的傳回類型相符。在上述範例中，這是以 `addPost` 類型形式傳回做為 `addedPost` 和 `Post` 而顯示。

若要在用戶端上設定訂閱，請參閱 [使用 Amplify 用戶端建置用戶端應用程式](building-a-client-app.md)。

## 使用訂閱引數
<a name="using-subscription-arguments"></a>

使用 GraphQL 訂閱的重要部分是了解何時及如何使用引數。您可以進行細微的變更，以修改通知用戶端發生變動的方式和時間。若要這樣做，請參閱快速入門章節的範例結構描述，該章節會建立「待辦事項」。對於此範例結構描述，定義了下列變動：

```
type Mutation {
    createTodo(input: CreateTodoInput!): Todo
    updateTodo(input: UpdateTodoInput!): Todo
    deleteTodo(input: DeleteTodoInput!): Todo
}
```

在預設範例中，用戶端可以使用`Todo``onUpdateTodo``subscription`沒有引數的 訂閱任何 的更新：

```
subscription OnUpdateTodo {
  onUpdateTodo {
    description
    id
    name
    when
  }
}
```

您可以使用其引數`subscription`來篩選您的 。例如，若要只在更新`todo`具有特定 `ID`的 `subscription`時觸發 ，請指定 `ID`值：

```
subscription OnUpdateTodo {
  onUpdateTodo(id: "a-todo-id") {
    description
    id
    name
    when
  }
}
```

您也可以傳遞多個引數。例如，以下`subscription`示範如何在特定位置和時間收到任何`Todo`更新的通知：

```
subscription todosAtHome {
  onUpdateTodo(when: "tomorrow", where: "at home") {
    description
    id
    name
    when
    where
  }
}
```

請注意，所有引數都是選用的。如果您未在 中指定任何引數`subscription`，則會訂閱應用程式中發生的所有`Todo`更新。不過，您可以更新 `subscription`的欄位定義，以要求 `ID`引數。這將強制特定 的回應，`todo`而不是所有 `todo`：

```
onUpdateTodo(
  id: ID!,
  name: String,
  when: String,
  where: String,
  description: String
): Todo
```

### 引數 Null 值具有意義
<a name="argument-null-value-has-meaning"></a>

進行訂閱查詢 in AWS AppSync 時，`null`引數值的篩選結果會與完全省略引數不同。

讓我們回到可建立待辦事項的待辦事項 API 範例。請參閱快速入門章節中的範例結構描述。

讓我們修改結構描述，在 `Todo`類型中包含描述擁有者身分的新`owner`欄位。欄位不是必要`owner`欄位，只能在 上設定`UpdateTodoInput`。請參閱下列簡化版本的結構描述：

```
type Todo {
  id: ID!
  name: String!
  when: String!
  where: String!
  description: String!
  owner: String
}

input CreateTodoInput {
  name: String!
  when: String!
  where: String!
  description: String!
}

input UpdateTodoInput {
  id: ID!
  name: String
  when: String
  where: String
  description: String
  owner: String
}

type Subscription {
    onUpdateTodo(
        id: ID,
        name: String,
        when: String,
        where: String,
        description: String
    ): Todo @aws_subscribe(mutations: ["updateTodo"])
}
```

下列訂閱會傳回所有`Todo`更新：

```
subscription MySubscription {
  onUpdateTodo {
    description
    id
    name
    when
    where
  }
}
```

如果您修改上述訂閱以新增欄位引數 `owner: null`，您現在會詢問不同的問題。此訂閱現在會註冊用戶端，以收到尚未提供擁有者的所有`Todo`更新通知。

```
subscription MySubscription {
  onUpdateTodo(owner: null) {
    description
    id
    name
    when
    where
  }
}
```

**注意**  
**自 2022 年 1 月 1 日起，MQTT over WebSockets 不再提供做為 GraphQL 訂閱 AWS AppSync APIs通訊協定。Pure WebSockets 是 中唯一支援的通訊協定 AWS AppSync。**  
以 AWS AppSync SDK 或 Amplify 程式庫為基礎的用戶端，在 2019 年 11 月之後發行，預設會自動使用純 WebSockets 將用戶端升級至最新版本可讓用戶端使用 AWS AppSync純 WebSockets 引擎。  
Pure WebSockets 隨附更大的承載大小 (240 KB)、更廣泛的用戶端選項，以及改善的 CloudWatch 指標。如需使用純 WebSocket 用戶端的詳細資訊，請參閱 [建置即時 WebSocket 用戶端 in AWS AppSync](real-time-websocket-client.md)。

# 在 中建立由無伺服器 WebSockets提供支援的一般 pub/sub APIs AWS AppSync
<a name="aws-appsync-real-time-create-generic-api-serverless-websocket"></a>

**重要**  
自 2025 年 3 月 13 日起，您可以使用 AWS AppSync Events 建置由 WebSockets 支援的即時 PubSub API。如需詳細資訊，請參閱《AppSync Events 開發人員指南》中的[透過 WebSocket 發佈](https://docs.aws.amazon.com/appsync/latest/eventapi/publish-websocket.html)事件。 *AWS AppSync *

有些應用程式只需要簡單的 WebSocket APIs其中用戶端會接聽特定的頻道或主題。沒有特定形狀或強烈類型需求的一般 JSON 資料可以推送到以純且簡單的發佈訂閱 (pub/sub) 模式收聽這些頻道之一的用戶端。

Use AWS AppSync 透過在 APIs 後端和用戶端上自動產生 GraphQL 程式碼，在幾分鐘內實作幾乎沒有 GraphQL 知識的簡單 pub/sub WebSocket API。 GraphQL 

## 建立和設定 pub-sub APIs
<a name="aws-appsync-real-time-enhanced-filtering-using-pub-sub-apis"></a>

若要開始使用，請執行下列動作：

1. 登入 AWS 管理主控台 並開啟 [AppSync 主控台](https://console.aws.amazon.com/appsync/)。

   1. 在**儀表板**上，選擇 **Create API (建立 API)**。

1. 在下一個畫面上，選擇**建立即時 API**，然後選擇**下一步**。

1. 為您的 pub/sub API 輸入易記的名稱。

1. 您可以啟用[私有 API](https://docs.aws.amazon.com/appsync/latest/devguide/using-private-apis.html) 功能，但我們建議暫時將其關閉。選擇**下一步**。

1. 您可以選擇使用 WebSockets 自動產生運作中的 pub/sub API。目前也建議您關閉此功能。選擇**下一步**。

1. 選擇**建立 API**，然後等待幾分鐘。將在您的帳戶中建立新的預先設定 AWS AppSync pub/sub API AWS 。

API 使用 AWS AppSync 的內建本機解析程式 （如需使用本機解析程式的詳細資訊，請參閱*AWS AppSync 開發人員指南*》中的[教學課程：本機解析程式](https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-local-resolvers-js.html)) 來管理多個臨時 pub/sub 通道和 WebSocket 連線，這些連線只會根據頻道名稱自動將資料交付和篩選至訂閱的用戶端。使用 API 金鑰授權 API 呼叫。

部署 API 之後，您會收到幾個額外的步驟來產生用戶端程式碼，並將其與您的用戶端應用程式整合。如需如何快速整合用戶端的範例，本指南將使用簡單的 React Web 應用程式。

1. 首先在本機電腦上使用 [NPM](https://www.npmjs.com/get-npm) 建立樣板 React 應用程式：

   ```
   $ npx create-react-app mypubsub-app 
   $ cd mypubsub-app
   ```
**注意**  
此範例使用 [Amplify 程式庫](https://docs.amplify.aws/lib/)將用戶端連線至後端 API。不過，您不需要在本機建立 Amplify CLI 專案。雖然 React 是此範例中選擇的用戶端，但 Amplify 程式庫也支援 iOS、Android 和 Flutter 用戶端，在這些不同的執行時間中提供相同的功能。支援的 Amplify 用戶端提供簡單的抽象概念，以幾行程式碼與 AWS AppSync GraphQL API 後端互動，包括內建 WebSocket 功能，完全相容於 [AWS AppSync 即時 WebSocket 通訊協定](https://docs.aws.amazon.com/appsync/latest/devguide/real-time-websocket-client.html)：  

   ```
   $ npm install @aws-amplify/api
   ```

1. 在 AWS AppSync 主控台中，選取 **JavaScript**，然後選取**下載**以下載具有 API 組態詳細資訊和產生 GraphQL 操作程式碼的單一檔案。

1. 將下載的檔案複製到 React 專案中的 `/src` 資料夾。

1. 接著，將現有樣板`src/App.js`檔案的內容取代為 主控台中可用的範例用戶端程式碼。

1. 使用下列命令在本機啟動應用程式：

   ```
   $ npm start
   ```

1. 若要測試傳送和接收即時資料，請開啟兩個瀏覽器視窗並存取 *localhost：3000*。範例應用程式設定為將一般 JSON 資料傳送至名為*機器人的*硬式編碼頻道。

1.  在其中一個瀏覽器視窗中，在文字方塊中輸入下列 JSON Blob，然後按一下**提交**：

   ```
   {
     "robot":"r2d2",
     "planet": "tatooine"
   }
   ```

這兩個瀏覽器執行個體都會訂閱*機器人*頻道，並即時接收發佈的資料，顯示在 Web 應用程式底部：

![\[pub/sub API 的 React 應用程式範例\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/pub-sub-react.png)


系統會自動產生所有必要的 GraphQL API 程式碼，包括結構描述、解析程式和操作，以啟用一般 pub/sub 使用案例。在後端，資料會發佈至具有 GraphQL 變動的 AWS AppSync 即時端點，如下所示：

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

訂閱者會使用相關的 GraphQL 訂閱存取傳送至特定臨時頻道的已發佈資料：

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

## 在現有應用程式中實作 pub-sub APIs
<a name="aws-appsync-real-time-enhanced-filtering-existing-apps"></a>

如果您只需要在現有應用程式中實作即時功能，這個一般 pub/sub API 組態可以輕鬆整合到任何應用程式或 API 技術。雖然使用單一 API 端點與 GraphQL 在單一網路呼叫中安全地存取、操作和合併來自一或多個資料來源的資料，但不需要從頭轉換或重建現有的 REST 型應用程式，以利用 AWS AppSync 的即時功能。例如，您可以在單獨的 API 端點中擁有現有的 CRUD 工作負載，用戶端只會將訊息或事件從現有應用程式傳送到一般 pub/sub API，以用於即時和 pub/sub 目的。

# 在 中定義增強型訂閱篩選條件 AWS AppSync
<a name="aws-appsync-real-time-enhanced-filtering"></a>

**重要**  
自 2025 年 3 月 13 日起，您可以使用 AWS AppSync Events 建置由 WebSockets 支援的即時 PubSub API。如需詳細資訊，請參閱《AppSync Events 開發人員指南》中的[透過 WebSocket 發佈](https://docs.aws.amazon.com/appsync/latest/eventapi/publish-websocket.html)事件。 *AWS AppSync *

在 中 AWS AppSync，您可以使用支援其他邏輯運算子的篩選條件，直接在 GraphQL API 訂閱解析程式中定義和啟用後端資料篩選的商業邏輯。您可以設定這些篩選條件，與用戶端中訂閱查詢上定義的訂閱引數不同。如需使用訂閱引數的詳細資訊，請參閱 [使用訂閱引數](aws-appsync-real-time-data.md#using-subscription-arguments)。如需運算子清單，請參閱 [AWS AppSync 解析程式映射範本公用程式參考](resolver-util-reference.md)。

基於本文件的目的，我們會將即時資料篩選分為下列類別：
+ **基本篩選** - 根據訂閱查詢中的用戶端定義引數進行篩選。
+ **增強型篩選** - 根據 AWS AppSync 服務後端中集中定義的邏輯進行篩選。

下列各節說明如何設定增強型訂閱篩選條件，並顯示其實際用途。

## 在 GraphQL 結構描述中定義訂閱
<a name="aws-appsync-real-time-enhanced-filtering-using-subscription-filters"></a>

若要使用增強型訂閱篩選條件，請在 GraphQL 結構描述中定義訂閱，然後使用篩選延伸來定義增強型篩選條件。若要說明增強型訂閱篩選的運作方式 AWS AppSync，請使用下列 GraphQL 結構描述，其定義票證管理系統 API，例如：

```
type Ticket {
	id: ID
	createdAt: AWSDateTime
	content: String
	severity: Int
	priority: Priority
	category: String
	group: String
	status: String
	
}

type Mutation {
	createTicket(input: TicketInput): Ticket
}

type Query {
	getTicket(id: ID!): Ticket
}

type Subscription {
	onSpecialTicketCreated: Ticket @aws_subscribe(mutations: ["createTicket"])
	onGroupTicketCreated(group: String!): Ticket @aws_subscribe(mutations: ["createTicket"])
}



enum Priority {
	none
	lowest
	low
	medium
	high
	highest
}

input TicketInput {
	content: String
	severity: Int
	priority: Priority
	category: String
	group: String
```

假設您為 API 建立`NONE`資料來源，然後使用此資料來源將解析程式連接到`createTicket`變動。您的處理常式可能如下所示：

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

export function request(ctx) {
	return {
		payload: {
			id: util.autoId(),
			createdAt: util.time.nowISO8601(),
			status: 'pending',
			...ctx.args.input,
		},
	};
}

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

**注意**  
增強型篩選條件會在指定訂閱的 GraphQL 解析程式處理常式中啟用。如需詳細資訊，請參閱[解析程式參考](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-js-version.html)。

若要實作增強型篩選條件的行為，您必須使用 `extensions.setSubscriptionFilter()`函數來定義篩選條件表達式，根據訂閱用戶端可能感興趣的 GraphQL 變動所發佈的資料進行評估。如需篩選延伸模組的詳細資訊，請參閱[延伸模組](https://docs.aws.amazon.com//appsync/latest/devguide/extensions-js.html)。

下一節說明如何使用篩選延伸來實作增強型篩選條件。

## 使用篩選延伸項目建立增強型訂閱篩選條件
<a name="aws-appsync-real-time-enhanced-filtering-defining-filters"></a>

增強型篩選條件會以 JSON 寫入訂閱解析程式的回應處理常式中。篩選條件可以分組在稱為 的清單中`filterGroup`。篩選條件是使用至少一個規則來定義，每個規則都有欄位、運算子和值。讓我們為 定義新的解析程式`onSpecialTicketCreated`，以設定增強型篩選條件。您可以在使用 AND 邏輯評估的篩選條件中設定多個規則，而篩選群組中的多個篩選條件則使用 OR 邏輯評估：

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

export function request(ctx) {
	// simplfy return null for the payload
	return { payload: null };
}

export function response(ctx) {
	const filter = {
		or: [
			{ severity: { ge: 7 }, priority: { in: ['high', 'medium'] } },
			{ category: { eq: 'security' }, group: { in: ['admin', 'operators'] } },
		],
	};
	extensions.setSubscriptionFilter(util.transform.toSubscriptionFilter(filter));

  // important: return null in the response
	return null;
}
```

根據上述範例中定義的篩選條件，如果票證是以下列方式建立，則會自動將重要票證推送至訂閱的 API 用戶端：
+ `priority` 關卡`high`或 `medium`

  AND 
+ `severity` 層級大於或等於 `7`(`ge`)

或 
+ `classification` 票證設定為 `Security` 

  AND 
+ `group` 指派設定為 `admin`或 `operators`

![\[顯示票證篩選查詢的範例\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/aws-priority-example.png)


訂閱解析程式中定義的篩選條件 （增強篩選） 優先於僅根據訂閱引數進行篩選 （基本篩選）。如需使用訂閱引數的詳細資訊，請參閱[使用訂閱引數](https://docs.aws.amazon.com//appsync/latest/devguide/aws-appsync-real-time-data.html#using-subscription-arguments))。

如果在訂閱的 GraphQL 結構描述中定義和需要 引數，則只有在引數在解析程式的 `extensions.setSubscriptionFilter()`方法中定義為規則時，才會根據指定的引數進行篩選。不過，如果訂閱解析程式中沒有`extensions`篩選方法，則用戶端中定義的引數只會用於基本篩選。您無法同時使用基本篩選和增強型篩選。

您可以使用訂閱篩選條件延伸邏輯中的 [`context`變數](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html)來存取請求的相關內容資訊。例如，使用 Amazon Cognito 使用者集區、OIDC 或 Lambda 自訂授權方進行授權時，您可以在建立訂閱`context.identity`時擷取 中使用者的相關資訊。您可以使用該資訊，根據使用者的身分建立篩選條件。

現在假設您想要實作 的增強型篩選條件行為`onGroupTicketCreated`。`onGroupTicketCreated` 訂閱需要強制`group`名稱做為 引數。建立時，票證會自動指派`pending`狀態。您可以設定訂閱篩選條件，只接收屬於所提供群組的新建立票證：

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

export function request(ctx) {
	// simplfy return null for the payload
	return { payload: null };
}

export function response(ctx) {
	const filter = { group: { eq: ctx.args.group }, status: { eq: 'pending' } };
	extensions.setSubscriptionFilter(util.transform.toSubscriptionFilter(filter));

	return null;
}
```

使用如下範例中的變動發佈資料時：

```
mutation CreateTicket {
  createTicket(input: {priority: medium, severity: 2, group: "aws"}) {
    id
    priority
    severity
    status
    group
    createdAt
  }
}
```

一旦建立具有`createTicket`變動的票證，訂閱的用戶端就會監聽透過 WebSockets 自動推送的資料：

```
subscription OnGroup {
  onGroupTicketCreated(group: "aws") {
    category
    status
    severity
    priority
    id
    group
    createdAt
    content
  }
}
```

無需引數即可訂閱用戶端，因為篩選邏輯是在 AWS AppSync 服務中使用增強型篩選實作，可簡化用戶端程式碼。只有在符合定義的篩選條件時，用戶端才會接收資料。

## 定義巢狀結構描述欄位的增強型篩選條件
<a name="aws-appsync-real-time-enhanced-filters-nested-schema-fields.title"></a>

您可以使用增強型訂閱篩選來篩選巢狀結構描述欄位。假設我們修改了上一節的結構描述，以包含位置和地址類型：

```
type Ticket {
	id: ID
	createdAt: AWSDateTime
	content: String
	severity: Int
	priority: Priority
	category: String
	group: String
	status: String
	location: ProblemLocation
}

type Mutation {
	createTicket(input: TicketInput): Ticket
}

type Query {
	getTicket(id: ID!): Ticket
}

type Subscription {
	onSpecialTicketCreated: Ticket @aws_subscribe(mutations: ["createTicket"])
	onGroupTicketCreated(group: String!): Ticket @aws_subscribe(mutations: ["createTicket"])
}

type ProblemLocation {
	address: Address
}

type Address {
	country: String
}

enum Priority {
	none
	lowest
	low
	medium
	high
	highest
}

input TicketInput {
	content: String
	severity: Int
	priority: Priority
	category: String
	group: String
	location: AWSJSON
```

透過此結構描述，您可以使用`.`分隔符號來表示巢狀化。下列範例會在 下新增巢狀結構描述欄位的篩選規則`location.address.country`。如果票證的地址設定為 ，則會觸發訂閱`USA`：

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

export const request = (ctx) => ({ payload: null });

export function response(ctx) {
	const filter = {
		or: [
			{ severity: { ge: 7 }, priority: { in: ['high', 'medium'] } },
			{ category: { eq: 'security' }, group: { in: ['admin', 'operators'] } },
			{ 'location.address.country': { eq: 'USA' } },
		],
	};
	extensions.setSubscriptionFilter(util.transform.toSubscriptionFilter(filter));
	return null;
}
```

在上述範例中， `location`代表巢狀層級一， `address` 代表巢狀層級二， `country`代表巢狀層級三，所有這些都由`.`分隔符號分隔。

您可以使用 `createTicket`變動測試此訂閱：

```
mutation CreateTicketInUSA {
  createTicket(input: {location: "{\"address\":{\"country\":\"USA\"}}"}) {
    category
    content
    createdAt
    group
    id
    location {
      address {
        country
      }
    }
    priority
    severity
    status
  }
}
```

## 從用戶端定義增強型篩選條件
<a name="aws-appsync-real-time-enhanced-filtering-defining-from-client"></a>

您可以在 GraphQL 中使用基本篩選搭配[訂閱引數](https://docs.aws.amazon.com/appsync/latest/devguide/aws-appsync-real-time-data.html#using-subscription-arguments)。在訂閱查詢中進行呼叫的用戶端會定義引數的值。在具有`extensions`篩選條件的 AWS AppSync 訂閱解析程式中啟用增強型篩選條件時，解析程式中定義的後端篩選條件會優先且優先。

使用訂閱中的`filter`引數設定動態、用戶端定義的增強型篩選條件。設定這些篩選條件時，您必須更新 GraphQL 結構描述以反映新引數：

```
...
type Subscription {
    onSpecialTicketCreated(filter: String): Ticket
        @aws_subscribe(mutations: ["createTicket"])
}
...
```

然後，用戶端可以傳送訂閱查詢，如下列範例所示：

```
subscription onSpecialTicketCreated($filter: String) {
     onSpecialTicketCreated(filter: $filter) {
        id
        group
        description
        priority
        severity
     }
 }
```

您可以設定查詢變數，如下列範例所示：

```
{"filter" : "{\"severity\":{\"le\":2}}"}
```

`util.transform.toSubscriptionFilter()` 解析程式公用程式可在訂閱回應映射範本中實作，以套用每個用戶端訂閱引數中定義的篩選條件：

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

export function request(ctx) {
	// simplfy return null for the payload
	return { payload: null };
}

export function response(ctx) {
	const filter = ctx.args.filter;
	extensions.setSubscriptionFilter(util.transform.toSubscriptionFilter(filter));
	return null;
}
```

透過此策略，用戶端可以定義自己的篩選條件，使用增強型篩選邏輯和其他運算子。當指定的用戶端在安全的 WebSocket 連線中調用訂閱查詢時，會指派篩選條件。如需增強型篩選之轉換公用程式的詳細資訊，包括`filter`查詢變數承載的格式，請參閱 [JavaScript 解析程式概觀](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html)。

## 其他增強型篩選限制
<a name="aws-appsync-real-time-enhanced-filtering-additional-restrictions"></a>

以下是幾個使用案例，其中對增強型篩選條件施加了額外的限制：
+ 增強型篩選條件不支援篩選最上層物件清單。在此使用案例中，增強型訂閱會忽略來自變動的已發佈資料。
+ AWS AppSync 最多支援五個巢狀層級。將忽略巢狀層級 5 以上結構描述欄位的篩選條件。使用以下 GraphQL 回應。`venue.address.country.metadata.continent` 允許 中的 `continent` 欄位，因為它是層級 5 巢狀。不過， `financial` `venue.address.country.metadata.capital.financial`是第六層巢狀，因此篩選條件無法運作：

  ```
  {
      "data": {
          "onCreateFilterEvent": {
              "venue": {
                  "address": {
                      "country": {
                          "metadata": {
                              "capital": {
                                  "financial": "New York"
                              },
                              "continent" : "North America"
                          }
                      },
                      "state": "WA"
                  },
                  "builtYear": 2023
              },
              "private": false,
          }
      }
  }
  ```

# 在 中使用篩選條件取消訂閱 WebSocket 連線 AWS AppSync
<a name="aws-appsync-real-time-invalidation"></a>

**重要**  
自 2025 年 3 月 13 日起，您可以使用 AWS AppSync Events 建置由 WebSockets 支援的即時 PubSub API。如需詳細資訊，請參閱《AppSync Events 開發人員指南》中的[透過 WebSocket 發佈](https://docs.aws.amazon.com/appsync/latest/eventapi/publish-websocket.html)事件。 *AWS AppSync *

在 中 AWS AppSync，您可以根據特定篩選邏輯，強制取消訂閱並關閉 （驗證） 已連線用戶端的 WebSocket 連線。這在授權相關案例中非常有用，例如當您從群組中移除使用者時。

訂閱失效是為了回應變動中定義的承載。我們建議您將用於使訂閱連線失效的變動視為 API 中的管理操作，並藉由限制其對管理員使用者、群組或後端服務的使用來相應地範圍許可。例如，使用結構描述授權指令，例如 `@aws_auth(cognito_groups: ["Administrators"])`或 `@aws_iam`。如需詳細資訊，請參閱[使用其他授權模式](https://docs.aws.amazon.com/appsync/latest/devguide/security-authz.html#using-additional-authorization-modes)。

失效篩選條件使用與[增強型訂閱篩選條件](https://docs.aws.amazon.com/appsync/latest/devguide/aws-appsync-real-time-enhanced-filtering.html)相同的語法和邏輯。使用下列公用程式定義這些篩選條件：
+ `extensions.invalidateSubscriptions()` – 在 GraphQL 解析程式的變動回應處理常式中定義。
+ `extensions.setSubscriptionInvalidationFilter()` – 在連結至變動之訂閱的 GraphQL 解析程式回應處理常式中定義。

如需失效篩選延伸模組的詳細資訊，請參閱 [JavaScript 解析程式概觀](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-overview-js.html)。

## 使用訂閱失效
<a name="aws-appsync-real-time-invalidation-using-invalidations"></a>

若要查看訂閱失效的運作方式 AWS AppSync，請使用下列 GraphQL 結構描述：

```
type User {
  userId: ID!
  groupId: ID!
}
    
type Group {
  groupId: ID!
  name: String!
  members: [ID!]!
}

type GroupMessage {
  userId: ID!
  groupId: ID!
  message: String!
}

type Mutation {
    createGroupMessage(userId: ID!, groupId : ID!, message: String!): GroupMessage
    removeUserFromGroup(userId: ID!, groupId : ID!) : User @aws_iam
}

type Subscription {
    onGroupMessageCreated(userId: ID!, groupId : ID!): GroupMessage
        @aws_subscribe(mutations: ["createGroupMessage"])
}

type Query {
	none: String
}
```

在`removeUserFromGroup`變動解析程式程式碼中定義失效篩選條件：

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

export function request(ctx) {
	return { payload: null };
}

export function response(ctx) {
	const { userId, groupId } = ctx.args;
	extensions.invalidateSubscriptions({
		subscriptionField: 'onGroupMessageCreated',
		payload: { userId, groupId },
	});
	return { userId, groupId };
}
```

調用變動時， `payload` 物件中定義的資料會用來取消訂閱 中定義的訂閱`subscriptionField`。失效篩選條件也會在`onGroupMessageCreated`訂閱的回應映射範本中定義。

如果`extensions.invalidateSubscriptions()`承載包含的 ID 符合篩選條件中定義的訂閱用戶端 IDs，則會取消訂閱對應的訂閱。此外，WebSocket 連線已關閉。定義訂閱的`onGroupMessageCreated`訂閱解析程式程式碼：

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

export function request(ctx) {
	// simplfy return null for the payload
	return { payload: null };
}

export function response(ctx) {
	const filter = { groupId: { eq: ctx.args.groupId } };
	extensions.setSubscriptionFilter(util.transform.toSubscriptionFilter(filter));

	const invalidation = { groupId: { eq: ctx.args.groupId }, userId: { eq: ctx.args.userId } };
	extensions.setSubscriptionInvalidationFilter(util.transform.toSubscriptionFilter(invalidation));

	return null;
}
```

請注意，訂閱回應處理常式可以同時定義訂閱篩選條件和失效篩選條件。

例如，假設用戶端 A `group-1`使用以下訂閱請求，將 ID 為 的新使用者訂閱`user-1`至 ID 為 的群組：

```
onGroupMessageCreated(userId : "user-1", groupId: :"group-1"){...}
```

AWS AppSync 會執行訂閱解析程式，產生上述`onGroupMessageCreated`回應映射範本中定義的訂閱和失效篩選條件。對於用戶端 A，訂閱篩選條件僅允許將資料傳送至 `group-1`，並同時為 `user-1`和 定義失效篩選條件`group-1`。

現在假設用戶端 B `group-2`使用以下訂閱請求，將 ID 為 的使用者訂閱`user-2`至 ID 為 的群組：

```
onGroupMessageCreated(userId : "user-2", groupId: :"group-2"){...}
```

AWS AppSync 會執行訂閱解析程式，產生訂閱和失效篩選條件。對於用戶端 B，訂閱篩選條件僅允許將資料傳送至 `group-2`，並同時為 `user-2`和 定義失效篩選條件`group-2`。

接著，假設具有 ID 的新群組訊息`message-1`是使用變動請求建立，如下列範例所示：

```
createGroupMessage(id: "message-1", groupId :
      "group-1", message: "test message"){...}
```

符合已定義篩選條件的訂閱用戶端會透過 WebSockets 自動接收下列資料承載：

```
{
  "data": {
    "onGroupMessageCreated": {
      "id": "message-1",
      "groupId": "group-1",
      "message": "test message",
    }
  }
}
```

用戶端 A 會收到訊息，因為篩選條件符合定義的訂閱篩選條件。不過，用戶端 B 不會收到訊息，因為使用者不屬於 `group-1`。此外，請求不符合訂閱解析程式中定義的訂閱篩選條件。

最後，假設 `user-1` `group-1`使用以下變動請求從 中移除：

```
removeUserFromGroup(userId: "user-1", groupId : "group-1"){...}
```

變動會啟動其`extensions.invalidateSubscriptions()`解析程式回應處理常式程式碼中定義的訂閱失效。 AWS AppSync 然後取消訂閱用戶端 A 並關閉其 WebSocket 連線。用戶端 B 不受影響，因為變動中定義的失效承載與其使用者或群組不相符。

當連線 AWS AppSync 失效時，用戶端會收到確認已取消訂閱的訊息：

```
{
  "message": "Subscription complete."
}
```

## 在訂閱失效篩選條件中使用內容變數
<a name="aws-appsync-real-time-invalidation-context"></a>

如同增強型訂閱篩選條件，您可以在訂閱失效篩選條件延伸中使用 [`context`變數](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html)來存取特定資料。

例如，您可以將電子郵件地址設定為變動中的失效承載，然後將其與使用 Amazon Cognito 使用者集區或 OpenID Connect 授權之訂閱使用者的電子郵件屬性或宣告進行比對。`extensions.setSubscriptionInvalidationFilter()` 訂閱失效程式中定義的失效篩選條件會檢查變動`extensions.invalidateSubscriptions()`承載設定的電子郵件地址是否與 中使用者 JWT 字符擷取的電子郵件地址相符`context.identity.claims.email`，進而啟動失效。

# 建置即時 WebSocket 用戶端 in AWS AppSync
<a name="real-time-websocket-client"></a>

**重要**  
自 2025 年 3 月 13 日起，您可以使用 AWS AppSync Events 建置由 WebSockets 支援的即時 PubSub API。如需詳細資訊，請參閱《AppSync Events 開發人員指南》中的[透過 WebSocket 發佈](https://docs.aws.amazon.com/appsync/latest/eventapi/publish-websocket.html)事件。 *AWS AppSync *

AWS AppSync 的即時 WebSocket 用戶端可透過多步驟程序啟用 GraphQL 訂閱。用戶端會先與 AWS AppSync 即時端點建立 WebSocket 連線、傳送連線初始化訊息，並等待確認。成功連線後，用戶端會透過傳送具有唯一 IDs和 GraphQL 查詢的開始訊息來註冊訂閱。 AWS AppSync 會以確認訊息確認成功訂閱。然後，用戶端會接聽由對應變動觸發的訂閱事件。為了維持連線， AWS AppSync 會定期傳送保持連線訊息。完成後，用戶端會透過傳送停止訊息來取消註冊訂閱。此系統支援單一 WebSocket 連線上的多個訂閱，並容納各種授權模式，包括 API 金鑰、Amazon Cognito 使用者集區、IAM 和 Lambda。

## GraphQL 訂閱的即時 WebSocket 用戶端實作
<a name="appsynclong-real-time-websocket-client-implementation-guide-for-graphql-subscriptions"></a>

下列序列圖和步驟顯示 WebSocket 用戶端、HTTP 用戶端和 AWS AppSync 之間的即時訂閱工作流程。

![\[Sequence diagram showing WebSocket client, AppSync endpoints, and HTTP client interactions for real-time subscriptions.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/realtime-client-flow.png)


1. 用戶端會與 AWS AppSync 即時端點建立 WebSocket 連線。如果存在網路錯誤，用戶端應該執行抖動的指數輪詢。如需詳細資訊，請參閱 AWS 架構部落格上的[指數退避和抖動](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/)。

1. （選用） 成功建立 WebSocket 連線後，用戶端會傳送訊息`connection_init`。

1. 如果 `connection_init` 已傳送，用戶端會等待來自 AWS AppSync `connection_ack`的訊息。此訊息包含 `connectionTimeoutMs` 參數，這是 `"ka"`（保持連線） 訊息的最大等待時間，以毫秒為單位。

1. AWS AppSync 會定期`"ka"`傳送訊息。用戶端會追蹤收到每則`"ka"`訊息的時間。如果用戶端未在`connectionTimeoutMs`幾毫秒內收到`"ka"`訊息，用戶端應該關閉連線。

1. 用戶端會透過傳送訂閱訊息來註冊 `start` 訂閱。單一 WebSocket 連線支援多個訂閱，即使它們處於不同的授權模式。

1. 用戶端等待 AWS AppSync `start_ack`傳送訊息以確認訂閱成功。如果發生錯誤， AWS AppSync 會傳回`"type": "error"`訊息。

1. 用戶端會接聽訂閱事件，這些事件會在呼叫對應的變動後傳送。查詢和變動通常會透過 `https://` 傳送至 AWS AppSync GraphQL 端點。訂閱會使用安全的 WebSocket () 流經 AWS AppSync 即時端點`wss://`。

1. 用戶端會透過傳送訂閱訊息來取消註冊 `stop` 訂閱。

1. 取消註冊所有訂閱並檢查沒有透過 WebSocket 傳輸的訊息後，用戶端可以斷開與 WebSocket 的連線。

## 建立 WebSocket 連線的交握詳情
<a name="handshake-details-to-establish-the-websocket-connection"></a>

若要使用 AWS AppSync 連接和啟動成功的交握，WebSocket 用戶端需要下列項目：
+ The AWS AppSync 即時端點
+ 標頭 – 包含與 AWS AppSync 端點和授權相關的資訊。 AWS AppSync 支援以下三種提供標頭的方法：
  + 透過查詢字串的標頭
    + 標頭資訊編碼為 base64 字串，衍生自字串化 JSON 物件。此 JSON 物件包含與 AWS AppSync 端點和授權相關的詳細資訊。JSON 物件的內容會根據授權模式而有所不同。
  + 透過 的標頭 `Sec-WebSocket-Protocol`
    + 來自字串化 JSON 物件的 base64Url-encoded字串，其中包含與 AWS AppSync 端點和授權相關的資訊，會在 `Sec-WebSocket-Protocol`標頭中做為通訊協定傳遞。JSON 物件的內容會根據授權模式而有所不同。
  + 透過標準 HTTP 標頭的標頭：
    + 標頭可以作為連線請求中的標準 HTTP 標頭傳遞，類似於 GraphQL 查詢和變動至 AWS AppSync 的標頭傳遞方式。不過，私有 API 連線請求不支援透過標準 HTTP 標頭傳遞標頭。
+  `payload` – Base64-encoded字串`payload`。只有在使用查詢字串提供標頭時，才需要承載

透過這些需求，WebSocket 用戶端可以連線至 URL，其中包含具有查詢字串的即時端點，使用 `graphql-ws`做為 WebSocket 通訊協定。

### 從 GraphQL 端點探索 即時端點
<a name="discovering-the-appsync-real-time-endpoint-from-the-appsync-graphql-endpoint"></a>

通訊協定和網域中的 AWS AppSync GraphQL 端點和 AWS AppSync 即時端點略有不同。您可以使用 AWS Command Line Interface (AWS CLI) 命令 擷取 GraphQL 端點`aws appsync get-graphql-api`。

****AWS AppSync GraphQL 端點：****  
 `https://example1234567890000.appsync-api.us-east-1.amazonaws.com/graphql`

****AWS AppSync 即時端點：****  
 `wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql`

應用程式可以使用任何 HTTP 用戶端來連線至 AWS AppSync GraphQL 端點 (`https://`) 進行查詢和變動。應用程式可以使用訂閱的任何 WebSocket 用戶端連線到 AWS AppSync 即時端點 (`wss://`)。

使用自訂網域名稱，您可以使用單一網域與兩個端點互動。例如，如果您將 `api.example.com`設定為自訂網域，則可以使用這些 URLs 與 GraphQL 和即時端點互動：

**AWS AppSync 自訂網域 GraphQL 端點：**  
`https://api.example.com/graphql`

**AWS AppSync 自訂網域即時端點：**  
`wss://api.example.com/graphql/realtime`

## 以 AWS AppSync API 授權模式為基礎的標頭參數格式
<a name="header-parameter-format-based-on-appsync-api-authorization-mode"></a>

連線查詢字串中使用的`header`物件格式會根據 AWS AppSync API 授權模式而有所不同。物件中的 `host` 欄位是指 AWS AppSync GraphQL 端點，即使對即時端點進行`wss://`呼叫，也會用來驗證連線。若要啟動交握並建立授權連線，`payload` 應該是空的 JSON 物件。只有在標頭透過查詢字串傳遞時，才需要承載。

下列各節示範每個授權模式的標頭格式。

### API 金鑰
<a name="api-key"></a>

#### API 金鑰標頭
<a name="api-key-list"></a>

**標頭內容**
+  `"host": <string>`： AWS AppSync GraphQL 端點的主機或您的自訂網域名稱。
+  `"x-api-key": <string>`：為 AWS AppSync API 設定的 API 金鑰。

**範例**

```
{
    "host":"example1234567890000.appsync-api.us-east-1.amazonaws.com",
    "x-api-key":"da2-12345678901234567890123456"
}
```

**透過查詢字串的標頭**

首先，包含 `host`和 的 JSON 物件`x-api-key`會轉換為字串。接下來，此字串會使用 base64 編碼進行編碼。產生的 base64 編碼字串會新增為名為 WebSocket URL `header`的查詢參數，以建立與 AWS AppSync 即時端點的連線。產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql?header=eyJob3N0IjoiZXhhbXBsZTEyMzQ1Njc4OTAwMDAuYXBwc3luYy1hcGkudXMtZWFzdC0xLmFtYXpvbmF3cy5jb20iLCJ4LWFtei1kYXRlIjoiMjAyMDA0MDFUMDAxMDEwWiIsIngtYXBpLWtleSI6ImRhMi16NHc0NHZoczV6Z2MzZHRqNXNranJsbGxqaSJ9&payload=e30=
```

請務必注意，除了 base64 編碼的標頭物件之外，空的 JSON 物件 \$1\$1 也是 base64 編碼的，並包含在 WebSocket URL `payload`中做為名為 的個別查詢參數。

**透過 的標頭 `Sec-WebSocket-Protocol`**

包含 `host`和 的 JSON 物件`x-api-key`會轉換為字串，然後使用 base64Url 編碼進行編碼。產生的 base64Url-encoded字串字首為 `header-`。在與 AWS AppSync 即時端點建立 WebSocket 連線時，除了 `Sec-WebSocket-Protocol`標頭`graphql-ws`中的 之外，此字首字串也會用作新的子通訊協定。

產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

`Sec-WebSocket-Protocol` 標頭包含下列值：

```
"sec-websocket-protocol" : ["graphql-ws", "header-ewogICAgImhvc3QiOiJleGFtcGxlMTIzNDU2Nzg5MDAwMC5hcHBzeW5jLWFwaS51cy1lYXN0LTEuYW1hem9uYXdzLmNvbSIsCiAgICAieC1hcGkta2V5IjoiZGEyLTEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Igp9"]
```

**透過標準 HTTP 標頭的標頭**

在此方法中，在與 AWS AppSync 即時端點建立 WebSocket 連線時，會使用標準 HTTP 標頭傳輸主機和 API 金鑰資訊。產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

請求標頭會包含下列項目：

```
"sec-websocket-protocol" : ["graphql-ws"]
"host":"example1234567890000.appsync-api.us-east-1.amazonaws.com",
"x-api-key":"da2-12345678901234567890123456"
```

### Amazon Cognito 使用者集區和 OpenID 連線 (OIDC)
<a name="amazon-cognito-user-pools-and-openid-connect-oidc"></a>

#### Amazon Cognito 和 OIDC 標頭
<a name="amazon-cognito-user-pools-and-openid-connect-oidc-list"></a>

標頭內容：
+  `"Authorization": <string>`：JWT ID 字符。標頭可以使用[承載結構](https://datatracker.ietf.org/doc/html/rfc6750#section-2.1)描述。
+  `"host": <string>`： AWS AppSync GraphQL 端點的主機或您的自訂網域名稱。

範例：

```
{
    "Authorization":"eyEXAMPLEiJjbG5xb3A5eW5MK09QYXIrMTJHWEFLSXBieU5WNHhsQjEXAMPLEnM2WldvPSIsImFsZyI6IlEXAMPLEn0.eyEXAMPLEiJhNmNmMjcwNy0xNjgxLTQ1NDItOWYxOC1lNjY0MTg2NjlkMzYiLCJldmVudF9pZCI6ImVkMzM5MmNkLWNjYTMtNGM2OC1hNDYyLTJlZGI3ZTNmY2FjZiIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE1Njk0NTc3MTgsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC5hcC1zb3V0aGVhc3QtMi5hbWF6b25hd3MuY29tXC9hcC1zb3V0aGVhc3QtMl83OHY0SVZibVAiLCJleHAiOjE1Njk0NjEzMjAsImlhdCI6MTU2OTQ1NzcyMCwianRpIjoiNTgzZjhmYmMtMzk2MS00YzA4LWJhZTAtYzQyY2IxMTM5NDY5IiwiY2xpZW50X2lkIjoiM3FlajVlMXZmMzd1N3RoZWw0dG91dDJkMWwiLCJ1c2VybmFtZSI6ImVsb3EXAMPLEn0.B4EXAMPLEFNpJ6ikVp7e6DRee95V6Qi-zEE2DJH7sHOl2zxYi7f-SmEGoh2AD8emxQRYajByz-rE4Jh0QOymN2Ys-ZIkMpVBTPgu-TMWDyOHhDUmUj2OP82yeZ3wlZAtr_gM4LzjXUXmI_K2yGjuXfXTaa1mvQEBG0mQfVd7SfwXB-jcv4RYVi6j25qgow9Ew52ufurPqaK-3WAKG32KpV8J4-Wejq8t0c-yA7sb8EnB551b7TU93uKRiVVK3E55Nk5ADPoam_WYE45i3s5qVAP_-InW75NUoOCGTsS8YWMfb6ecHYJ-1j-bzA27zaT9VjctXn9byNFZmEXAMPLExw",
    "host":"example1234567890000.appsync-api.us-east-1.amazonaws.com"
}
```

**透過查詢字串的標頭**

首先，包含 `host`和 的 JSON 物件`Authorization`會轉換為字串。接下來，此字串會使用 base64 編碼進行編碼。產生的 base64 編碼字串會新增為名為 WebSocket URL `header`的查詢參數，以建立與 AWS AppSync 即時端點的連線。產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql?header=eyJBdXRob3JpemF0aW9uIjoiZXlKcmFXUWlPaUpqYkc1eGIzQTVlVzVNSzA5UVlYSXJNVEpIV0VGTFNYQmllVTVXTkhoc1FqaFBWVzlZTW5NMldsZHZQU0lzSW1Gc1p5STZJbEpUTWpVMkluMC5leUp6ZFdJaU9pSmhObU5tTWpjd055MHhOamd4TFRRMU5ESXRPV1l4T0MxbE5qWTBNVGcyTmpsa016WWlMQ0psZG1WdWRGOXBaQ0k2SW1Wa016TTVNbU5rTFdOallUTXROR00yT0MxaE5EWXlMVEpsWkdJM1pUTm1ZMkZqWmlJc0luUnZhMlZ1WDNWelpTSTZJbUZqWTJWemN5SXNJbk5qYjNCbElqb2lZWGR6TG1OdloyNXBkRzh1YzJsbmJtbHVMblZ6WlhJdVlXUnRhVzRpTENKaGRYUm9YM1JwYldVaU9qRTFOamswTlRjM01UZ3NJbWx6Y3lJNkltaDBkSEJ6T2x3dlhDOWpiMmR1YVhSdkxXbGtjQzVoY0MxemIzVjBhR1ZoYzNRdE1pNWhiV0Y2YjI1aGQzTXVZMjl0WEM5aGNDMXpiM1YwYUdWaGMzUXRNbDgzT0hZMFNWWmliVkFpTENKbGVIQWlPakUxTmprME5qRXpNakFzSW1saGRDSTZNVFUyT1RRMU56Y3lNQ3dpYW5ScElqb2lOVGd6WmpobVltTXRNemsyTVMwMFl6QTRMV0poWlRBdFl6UXlZMkl4TVRNNU5EWTVJaXdpWTJ4cFpXNTBYMmxrSWpvaU0zRmxhalZsTVhabU16ZDFOM1JvWld3MGRHOTFkREprTVd3aUxDSjFjMlZ5Ym1GdFpTSTZJbVZzYjNKNllXWmxJbjAuQjRjZEp0aDNLRk5wSjZpa1ZwN2U2RFJlZTk1VjZRaS16RUUyREpIN3NIT2wyenhZaTdmLVNtRUdvaDJBRDhlbXhRUllhakJ5ei1yRTRKaDBRT3ltTjJZcy1aSWtNcFZCVFBndS1UTVdEeU9IaERVbVVqMk9QODJ5ZVozd2xaQXRyX2dNNEx6alhVWG1JX0syeUdqdVhmWFRhYTFtdlFFQkcwbVFmVmQ3U2Z3WEItamN2NFJZVmk2ajI1cWdvdzlFdzUydWZ1clBxYUstM1dBS0czMktwVjhKNC1XZWpxOHQwYy15QTdzYjhFbkI1NTFiN1RVOTN1S1JpVlZLM0U1NU5rNUFEUG9hbV9XWUU0NWkzczVxVkFQXy1Jblc3NU5Vb09DR1RzUzhZV01mYjZlY0hZSi0xai1iekEyN3phVDlWamN0WG45YnlORlptS0xwQTJMY3h3IiwiaG9zdCI6ImV4YW1wbGUxMjM0NTY3ODkwMDAwLmFwcHN5bmMtYXBpLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tIn0=&payload=e30=
```

請務必注意，除了 base64 編碼的標頭物件之外，空的 JSON 物件 \$1\$1 也是 base64 編碼的，並包含在 WebSocket URL `payload`中做為名為 的個別查詢參數。

**透過 的標頭 `Sec-WebSocket-Protocol`**

包含 `host`和 的 JSON 物件`Authorization`會轉換為字串，然後使用 base64Url 編碼進行編碼。產生的 base64Url-encoded字串字首為 `header-`。在與 AWS AppSync 即時端點建立 WebSocket 連線時，除了 `Sec-WebSocket-Protocol`標頭`graphql-ws`中的 之外，此字首字串也會用作新的子通訊協定。

產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

`Sec-WebSocket-Protocol` 標頭包含下列值：

```
"sec-websocket-protocol" : ["graphql-ws", "header-ewogICAgImhvc3QiOiJleGFtcGxlMTIzNDU2Nzg5MDAwMC5hcHBzeW5jLWFwaS51cy1lYXN0LTEuYW1hem9uYXdzLmNvbSIsCiAgICAieC1hcGkta2V5IjoiZGEyLTEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Igp9"]
```

**透過標準 HTTP 標頭的標頭**

在此方法中，在與 AWS AppSync 即時端點建立 WebSocket 連線時，會使用標準 HTTP 標頭傳輸主機和授權資訊。產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

請求標頭會包含下列項目：

```
"sec-websocket-protocol" : ["graphql-ws"]
"Authorization":"eyEXAMPLEiJjbG5xb3A5eW5MK09QYXIrMTJHWEFLSXBieU5WNHhsQjEXAMPLEnM2WldvPSIsImFsZyI6IlEXAMPLEn0.eyEXAMPLEiJhNmNmMjcwNy0xNjgxLTQ1NDItOWYxOC1lNjY0MTg2NjlkMzYiLCJldmVudF9pZCI6ImVkMzM5MmNkLWNjYTMtNGM2OC1hNDYyLTJlZGI3ZTNmY2FjZiIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE1Njk0NTc3MTgsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC5hcC1zb3V0aGVhc3QtMi5hbWF6b25hd3MuY29tXC9hcC1zb3V0aGVhc3QtMl83OHY0SVZibVAiLCJleHAiOjE1Njk0NjEzMjAsImlhdCI6MTU2OTQ1NzcyMCwianRpIjoiNTgzZjhmYmMtMzk2MS00YzA4LWJhZTAtYzQyY2IxMTM5NDY5IiwiY2xpZW50X2lkIjoiM3FlajVlMXZmMzd1N3RoZWw0dG91dDJkMWwiLCJ1c2VybmFtZSI6ImVsb3EXAMPLEn0.B4EXAMPLEFNpJ6ikVp7e6DRee95V6Qi-zEE2DJH7sHOl2zxYi7f-SmEGoh2AD8emxQRYajByz-rE4Jh0QOymN2Ys-ZIkMpVBTPgu-TMWDyOHhDUmUj2OP82yeZ3wlZAtr_gM4LzjXUXmI_K2yGjuXfXTaa1mvQEBG0mQfVd7SfwXB-jcv4RYVi6j25qgow9Ew52ufurPqaK-3WAKG32KpV8J4-Wejq8t0c-yA7sb8EnB551b7TU93uKRiVVK3E55Nk5ADPoam_WYE45i3s5qVAP_-InW75NUoOCGTsS8YWMfb6ecHYJ-1j-bzA27zaT9VjctXn9byNFZmEXAMPLExw",
"host":"example1234567890000.appsync-api.us-east-1.amazonaws.com"
```

### IAM
<a name="iam"></a>

#### IAM 標頭
<a name="iam-list"></a>

**標頭內容**
+  `"accept": "application/json, text/javascript"`：常數 `<string>` 參數。
+  `"content-encoding": "amz-1.0"`：常數 `<string>` 參數。
+  `"content-type": "application/json; charset=UTF-8"`：常數 `<string>` 參數。
+  `"host": <string>`：這是 AWS AppSync GraphQL 端點的主機。
  + `"x-amz-date": <string>`：時間戳記必須是 UTC 和下列 ISO 8601 格式：YYYYMMDD'T'HHMMSS'Z'。例如，20150830T123600Z 是有效的時間戳記。不包含時間戳記的毫秒數。如需詳細資訊，請參閱《[》中的 Signature 第 4 版中的處理日期](https://docs.aws.amazon.com/general/latest/gr/sigv4-date-handling.html)*AWS 一般參考*。
  +  `"X-Amz-Security-Token": <string>`： AWS 工作階段字符，使用臨時安全登入資料時需要。如需詳細資訊，請參閱《IAM 使用者指南》**中的[搭配使用暫時憑證與 AWS 資源](https://docs.aws.amazon.com//IAM/latest/UserGuide/id_credentials_temp_use-resources.html)。
  +  `"Authorization": <string>`： AWS AppSync 端點的簽章第 4 版 (SigV4) 簽署資訊。如需簽署程序的詳細資訊，請參閱《》中的[任務 4：將簽章新增至 HTTP 請求](https://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to-request.html)*AWS 一般參考*。

SigV4 簽署 HTTP 請求包含正式 URL，這是`/connect`附加 的 AWS AppSync GraphQL 端點。服務端點 AWS 區域與您使用 AWS AppSync API 的區域相同，且服務名稱為 'appsync'。要簽署的 HTTP 請求如下：

```
{
  url: "https://example1234567890000.appsync-api.us-east-1.amazonaws.com/graphql/connect",
  data: "{}",
  method: "POST",
  headers: {
    "accept": "application/json, text/javascript",
    "content-encoding": "amz-1.0",
    "content-type": "application/json; charset=UTF-8",
  }
}
```

**範例**

```
{
  "accept": "application/json, text/javascript",
  "content-encoding": "amz-1.0",
  "content-type": "application/json; charset=UTF-8",
  "host": "example1234567890000.appsync-api.us-east-1.amazonaws.com",
  "x-amz-date": "20200401T001010Z",
  "X-Amz-Security-Token": "AgEXAMPLEZ2luX2VjEAoaDmFwLXNvdXRoZWFEXAMPLEcwRQIgAh97Cljq7wOPL8KsxP3YtDuyc/9hAj8PhJ7Fvf38SgoCIQDhJEXAMPLEPspioOztj++pEagWCveZUjKEn0zyUhBEXAMPLEjj//////////8BEXAMPLExODk2NDgyNzg1NSIMo1mWnpESWUoYw4BkKqEFSrm3DXuL8w+ZbVc4JKjDP4vUCKNR6Le9C9pZp9PsW0NoFy3vLBUdAXEXAMPLEOVG8feXfiEEA+1khgFK/wEtwR+9zF7NaMMMse07wN2gG2tH0eKMEXAMPLEQX+sMbytQo8iepP9PZOzlZsSFb/dP5Q8hk6YEXAMPLEYcKZsTkDAq2uKFQ8mYUVA9EtQnNRiFLEY83aKvG/tqLWNnGlSNVx7SMcfovkFDqQamm+88y1OwwAEYK7qcoceX6Z7GGcaYuIfGpaX2MCCELeQvZ+8WxEgOnIfz7GYvsYNjLZSaRnV4G+ILY1F0QNW64S9Nvj+BwDg3ht2CrNvpwjVYlj9U3nmxE0UG5ne83LL5hhqMpm25kmL7enVgw2kQzmU2id4IKu0C/WaoDRuO2F5zE63vJbxN8AYs7338+4B4HBb6BZ6OUgg96Q15RA41/gIqxaVPxyTpDfTU5GfSLxocdYeniqqpFMtZG2n9d0u7GsQNcFkNcG3qDZm4tDo8tZbuym0a2VcF2E5hFEgXBa+XLJCfXi/77OqAEjP0x7Qdk3B43p8KG/BaioP5RsV8zBGvH1zAgyPha2rN70/tT13yrmPd5QYEfwzexjKrV4mWIuRg8NTHYSZJUaeyCwTom80VFUJXG+GYTUyv5W22aBcnoRGiCiKEYTLOkgXecdKFTHmcIAejQ9Welr0a196Kq87w5KNMCkcCGFnwBNFLmfnbpNqT6rUBxxs3X5ntX9d8HVtSYINTsGXXMZCJ7fnbWajhg/aox0FtHX21eF6qIGT8j1z+l2opU+ggwUgkhUUgCH2TfqBj+MLMVVvpgqJsPKt582caFKArIFIvO+9QupxLnEH2hz04TMTfnU6bQC6z1buVe7h+tOLnh1YPFsLQ88anib/7TTC8k9DsBTq0ASe8R2GbSEsmO9qbbMwgEaYUhOKtGeyQsSJdhSk6XxXThrWL9EnwBCXDkICMqdntAxyyM9nWsZ4bL9JHqExgWUmfWChzPFAqn3F4y896UqHTZxlq3WGypn5HHcem2Hqf3IVxKH1inhqdVtkryEiTWrI7ZdjbqnqRbl+WgtPtKOOweDlCaRs3R2qXcbNgVhleMk4IWnF8D1695AenU1LwHjOJLkCjxgNFiWAFEPH9aEXAMPLExA==",
  "Authorization": "AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXXXXXXXXX/20200401/us-east-1/appsync/aws4_request, SignedHeaders=accept;content-encoding;content-type;host;x-amz-date;x-amz-security-token, Signature=83EXAMPLEbcc1fe3ee69f75cd5ebbf4cb4f150e4f99cec869f149c5EXAMPLEdc"
}
```

**透過查詢字串的標頭**

首先，包含 `host`(AWS AppSync GraphQL 端點） 和其他授權標頭的 JSON 物件會轉換為字串。接下來，此字串會使用 base64 編碼進行編碼。產生的 base64 編碼字串會新增至 WebSocket URL，做為名為 的查詢參數`header`。產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql?header=eyJBdXRob3JpemF0aW9uIjoiZXlKcmFXUWlPaUpqYkc1eGIzQTVlVzVNSzA5UVlYSXJNVEpIV0VGTFNYQmllVTVXTkhoc1FqaFBWVzlZTW5NMldsZHZQU0lzSW1Gc1p5STZJbEpUTWpVMkluMC5leUp6ZFdJaU9pSmhObU5tTWpjd055MHhOamd4TFRRMU5ESXRPV1l4T0MxbE5qWTBNVGcyTmpsa016WWlMQ0psZG1WdWRGOXBaQ0k2SW1Wa016TTVNbU5rTFdOallUTXROR00yT0MxaE5EWXlMVEpsWkdJM1pUTm1ZMkZqWmlJc0luUnZhMlZ1WDNWelpTSTZJbUZqWTJWemN5SXNJbk5qYjNCbElqb2lZWGR6TG1OdloyNXBkRzh1YzJsbmJtbHVMblZ6WlhJdVlXUnRhVzRpTENKaGRYUm9YM1JwYldVaU9qRTFOamswTlRjM01UZ3NJbWx6Y3lJNkltaDBkSEJ6T2x3dlhDOWpiMmR1YVhSdkxXbGtjQzVoY0MxemIzVjBhR1ZoYzNRdE1pNWhiV0Y2YjI1aGQzTXVZMjl0WEM5aGNDMXpiM1YwYUdWaGMzUXRNbDgzT0hZMFNWWmliVkFpTENKbGVIQWlPakUxTmprME5qRXpNakFzSW1saGRDSTZNVFUyT1RRMU56Y3lNQ3dpYW5ScElqb2lOVGd6WmpobVltTXRNemsyTVMwMFl6QTRMV0poWlRBdFl6UXlZMkl4TVRNNU5EWTVJaXdpWTJ4cFpXNTBYMmxrSWpvaU0zRmxhalZsTVhabU16ZDFOM1JvWld3MGRHOTFkREprTVd3aUxDSjFjMlZ5Ym1GdFpTSTZJbVZzYjNKNllXWmxJbjAuQjRjZEp0aDNLRk5wSjZpa1ZwN2U2RFJlZTk1VjZRaS16RUUyREpIN3NIT2wyenhZaTdmLVNtRUdvaDJBRDhlbXhRUllhakJ5ei1yRTRKaDBRT3ltTjJZcy1aSWtNcFZCVFBndS1UTVdEeU9IaERVbVVqMk9QODJ5ZVozd2xaQXRyX2dNNEx6alhVWG1JX0syeUdqdVhmWFRhYTFtdlFFQkcwbVFmVmQ3U2Z3WEItamN2NFJZVmk2ajI1cWdvdzlFdzUydWZ1clBxYUstM1dBS0czMktwVjhKNC1XZWpxOHQwYy15QTdzYjhFbkI1NTFiN1RVOTN1S1JpVlZLM0U1NU5rNUFEUG9hbV9XWUU0NWkzczVxVkFQXy1Jblc3NU5Vb09DR1RzUzhZV01mYjZlY0hZSi0xai1iekEyN3phVDlWamN0WG45YnlORlptS0xwQTJMY3h3IiwiaG9zdCI6ImV4YW1wbGUxMjM0NTY3ODkwMDAwLmFwcHN5bmMtYXBpLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tIn0=&payload=e30=
```

請務必注意，除了 base64 編碼的標頭物件之外，空的 JSON 物件 \$1\$1 也是 base64 編碼的，並包含在 WebSocket URL `payload`中做為名為 的個別查詢參數。

**透過 的標頭 `Sec-WebSocket-Protocol`**

包含 和其他授權標頭`host`的 JSON 物件會轉換為字串，然後使用 base64Url 編碼進行編碼。產生的 base64Url-encoded字串字首為 `header-`。在與 AWS AppSync 即時端點建立 WebSocket 連線時，除了 `Sec-WebSocket-Protocol`標頭`graphql-ws`中的 之外，此字首字串也會用作新的子通訊協定。

產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

`Sec-WebSocket-Protocol` 標頭包含下列值：

```
"sec-websocket-protocol" : ["graphql-ws", "header-ew0KICAiYWNjZXB0IjogImFwcGxpY2F0aW9uL2pzb24sIHRleHQvamF2YXNjcmlwdCIsDQogICJjb250ZW50LWVuY29kaW5nIjogImFtei0xLjAiLA0KICAiY29udGVudC10eXBlIjogImFwcGxpY2F0aW9uL2pzb247IGNoYXJzZXQ9VVRGLTgiLA0KICAiaG9zdCI6ICJleGFtcGxlMTIzNDU2Nzg5MDAwMC5hcHBzeW5jLWFwaS51cy1lYXN0LTEuYW1hem9uYXdzLmNvbSIsDQogICJ4LWFtei1kYXRlIjogIjIwMjAwNDAxVDAwMTAxMFoiLA0KICAiWC1BbXotU2VjdXJpdHktVG9rZW4iOiAiQWdFWEFNUExFWjJsdVgyVmpFQW9hRG1Gd0xYTnZkWFJvWldGRVhBTVBMRWN3UlFJZ0FoOTdDbGpxN3dPUEw4S3N4UDNZdER1eWMvOWhBajhQaEo3RnZmMzhTZ29DSVFEaEpFWEFNUExFUHNwaW9PenRqKytwRWFnV0N2ZVpVaktFbjB6eVVoQkVYQU1QTEVqai8vLy8vLy8vLy84QkVYQU1QTEV4T0RrMk5EZ3lOemcxTlNJTW8xbVducEVTV1VvWXc0QmtLcUVGU3JtM0RYdUw4dytaYlZjNEpLakRQNHZVQ0tOUjZMZTlDOXBacDlQc1cwTm9GeTN2TEJVZEFYRVhBTVBMRU9WRzhmZVhmaUVFQSsxa2hnRksvd0V0d1IrOXpGN05hTU1Nc2UwN3dOMmdHMnRIMGVLTUVYQU1QTEVRWCtzTWJ5dFFvOGllcFA5UFpPemxac1NGYi9kUDVROGhrNllFWEFNUExFWWNLWnNUa0RBcTJ1S0ZROG1ZVVZBOUV0UW5OUmlGTEVZODNhS3ZHL3RxTFdObkdsU05WeDdTTWNmb3ZrRkRxUWFtbSs4OHkxT3d3QUVZSzdxY29jZVg2WjdHR2NhWXVJZkdwYVgyTUNDRUxlUXZaKzhXeEVnT25JZno3R1l2c1lOakxaU2FSblY0RytJTFkxRjBRTlc2NFM5TnZqK0J3RGczaHQyQ3JOdnB3alZZbGo5VTNubXhFMFVHNW5lODNMTDVoaHFNcG0yNWttTDdlblZndzJrUXptVTJpZDRJS3UwQy9XYW9EUnVPMkY1ekU2M3ZKYnhOOEFZczczMzgrNEI0SEJiNkJaNk9VZ2c5NlExNVJBNDEvZ0lxeGFWUHh5VHBEZlRVNUdmU0x4b2NkWWVuaXFxcEZNdFpHMm45ZDB1N0dzUU5jRmtOY0czcURabTR0RG84dFpidXltMGEyVmNGMkU1aEZFZ1hCYStYTEpDZlhpLzc3T3FBRWpQMHg3UWRrM0I0M3A4S0cvQmFpb1A1UnNWOHpCR3ZIMXpBZ3lQaGEyck43MC90VDEzeXJtUGQ1UVlFZnd6ZXhqS3JWNG1XSXVSZzhOVEhZU1pKVWFleUN3VG9tODBWRlVKWEcrR1lUVXl2NVcyMmFCY25vUkdpQ2lLRVlUTE9rZ1hlY2RLRlRIbWNJQWVqUTlXZWxyMGExOTZLcTg3dzVLTk1Da2NDR0Zud0JORkxtZm5icE5xVDZyVUJ4eHMzWDVudFg5ZDhIVnRTWUlOVHNHWFhNWkNKN2ZuYldhamhnL2FveDBGdEhYMjFlRjZxSUdUOGoxeitsMm9wVStnZ3dVZ2toVVVnQ0gyVGZxQmorTUxNVlZ2cGdxSnNQS3Q1ODJjYUZLQXJJRkl2Tys5UXVweExuRUgyaHowNFRNVGZuVTZiUUM2ejFidVZlN2grdE9MbmgxWVBGc0xRODhhbmliLzdUVEM4azlEc0JUcTBBU2U4UjJHYlNFc21POXFiYk13Z0VhWVVoT0t0R2V5UXNTSmRoU2s2WHhYVGhyV0w5RW53QkNYRGtJQ01xZG50QXh5eU05bldzWjRiTDlKSHFFeGdXVW1mV0NoelBGQXFuM0Y0eTg5NlVxSFRaeGxxM1dHeXBuNUhIY2VtMkhxZjNJVnhLSDFpbmhxZFZ0a3J5RWlUV3JJN1pkamJxbnFSYmwrV2d0UHRLT093ZURsQ2FSczNSMnFYY2JOZ1ZobGVNazRJV25GOEQxNjk1QWVuVTFMd0hqT0pMa0NqeGdORmlXQUZFUEg5YUVYQU1QTEV4QT09IiwNCiAgIkF1dGhvcml6YXRpb24iOiAiQVdTNC1ITUFDLVNIQTI1NiBDcmVkZW50aWFsPVhYWFhYWFhYWFhYWFhYWFhYWFgvMjAyMDA0MDEvdXMtZWFzdC0xL2FwcHN5bmMvYXdzNF9yZXF1ZXN0LCBTaWduZWRIZWFkZXJzPWFjY2VwdDtjb250ZW50LWVuY29kaW5nO2NvbnRlbnQtdHlwZTtob3N0O3gtYW16LWRhdGU7eC1hbXotc2VjdXJpdHktdG9rZW4sIFNpZ25hdHVyZT04M0VYQU1QTEViY2MxZmUzZWU2OWY3NWNkNWViYmY0Y2I0ZjE1MGU0Zjk5Y2VjODY5ZjE0OWM1RVhBTVBMRWRjIg0KfQ"]
```

**透過標準 HTTP 標頭的標頭**

在此方法中，在與 AWS AppSync 即時端點建立 WebSocket 連線時，會使用標準 HTTP 標頭傳輸主機和其他授權資訊。產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

請求標頭會包含下列項目：

```
"sec-websocket-protocol" : ["graphql-ws"]
"accept": "application/json, text/javascript",
"content-encoding": "amz-1.0",
"content-type": "application/json; charset=UTF-8",
"host": "example1234567890000.appsync-api.us-east-1.amazonaws.com",
"x-amz-date": "20200401T001010Z",
"X-Amz-Security-Token": "AgEXAMPLEZ2luX2VjEAoaDmFwLXNvdXRoZWFEXAMPLEcwRQIgAh97Cljq7wOPL8KsxP3YtDuyc/9hAj8PhJ7Fvf38SgoCIQDhJEXAMPLEPspioOztj++pEagWCveZUjKEn0zyUhBEXAMPLEjj//////////8BEXAMPLExODk2NDgyNzg1NSIMo1mWnpESWUoYw4BkKqEFSrm3DXuL8w+ZbVc4JKjDP4vUCKNR6Le9C9pZp9PsW0NoFy3vLBUdAXEXAMPLEOVG8feXfiEEA+1khgFK/wEtwR+9zF7NaMMMse07wN2gG2tH0eKMEXAMPLEQX+sMbytQo8iepP9PZOzlZsSFb/dP5Q8hk6YEXAMPLEYcKZsTkDAq2uKFQ8mYUVA9EtQnNRiFLEY83aKvG/tqLWNnGlSNVx7SMcfovkFDqQamm+88y1OwwAEYK7qcoceX6Z7GGcaYuIfGpaX2MCCELeQvZ+8WxEgOnIfz7GYvsYNjLZSaRnV4G+ILY1F0QNW64S9Nvj+BwDg3ht2CrNvpwjVYlj9U3nmxE0UG5ne83LL5hhqMpm25kmL7enVgw2kQzmU2id4IKu0C/WaoDRuO2F5zE63vJbxN8AYs7338+4B4HBb6BZ6OUgg96Q15RA41/gIqxaVPxyTpDfTU5GfSLxocdYeniqqpFMtZG2n9d0u7GsQNcFkNcG3qDZm4tDo8tZbuym0a2VcF2E5hFEgXBa+XLJCfXi/77OqAEjP0x7Qdk3B43p8KG/BaioP5RsV8zBGvH1zAgyPha2rN70/tT13yrmPd5QYEfwzexjKrV4mWIuRg8NTHYSZJUaeyCwTom80VFUJXG+GYTUyv5W22aBcnoRGiCiKEYTLOkgXecdKFTHmcIAejQ9Welr0a196Kq87w5KNMCkcCGFnwBNFLmfnbpNqT6rUBxxs3X5ntX9d8HVtSYINTsGXXMZCJ7fnbWajhg/aox0FtHX21eF6qIGT8j1z+l2opU+ggwUgkhUUgCH2TfqBj+MLMVVvpgqJsPKt582caFKArIFIvO+9QupxLnEH2hz04TMTfnU6bQC6z1buVe7h+tOLnh1YPFsLQ88anib/7TTC8k9DsBTq0ASe8R2GbSEsmO9qbbMwgEaYUhOKtGeyQsSJdhSk6XxXThrWL9EnwBCXDkICMqdntAxyyM9nWsZ4bL9JHqExgWUmfWChzPFAqn3F4y896UqHTZxlq3WGypn5HHcem2Hqf3IVxKH1inhqdVtkryEiTWrI7ZdjbqnqRbl+WgtPtKOOweDlCaRs3R2qXcbNgVhleMk4IWnF8D1695AenU1LwHjOJLkCjxgNFiWAFEPH9aEXAMPLExA==",
"Authorization": "AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXXXXXXXXX/20200401/us-east-1/appsync/aws4_request, SignedHeaders=accept;content-encoding;content-type;host;x-amz-date;x-amz-security-token, Signature=83EXAMPLEbcc1fe3ee69f75cd5ebbf4cb4f150e4f99cec869f149c5EXAMPLEdc"
```

若要使用自訂網域簽署請求：

```
{
  url: "https://api.example.com/graphql/connect",
  data: "{}",
  method: "POST",
  headers: {
    "accept": "application/json, text/javascript",
    "content-encoding": "amz-1.0",
    "content-type": "application/json; charset=UTF-8",
  }
}
```

**範例**

```
{
  "accept": "application/json, text/javascript",
  "content-encoding": "amz-1.0",
  "content-type": "application/json; charset=UTF-8",
  "host": "api.example.com",
  "x-amz-date": "20200401T001010Z",
  "X-Amz-Security-Token": "AgEXAMPLEZ2luX2VjEAoaDmFwLXNvdXRoZWFEXAMPLEcwRQIgAh97Cljq7wOPL8KsxP3YtDuyc/9hAj8PhJ7Fvf38SgoCIQDhJEXAMPLEPspioOztj++pEagWCveZUjKEn0zyUhBEXAMPLEjj//////////8BEXAMPLExODk2NDgyNzg1NSIMo1mWnpESWUoYw4BkKqEFSrm3DXuL8w+ZbVc4JKjDP4vUCKNR6Le9C9pZp9PsW0NoFy3vLBUdAXEXAMPLEOVG8feXfiEEA+1khgFK/wEtwR+9zF7NaMMMse07wN2gG2tH0eKMEXAMPLEQX+sMbytQo8iepP9PZOzlZsSFb/dP5Q8hk6YEXAMPLEYcKZsTkDAq2uKFQ8mYUVA9EtQnNRiFLEY83aKvG/tqLWNnGlSNVx7SMcfovkFDqQamm+88y1OwwAEYK7qcoceX6Z7GGcaYuIfGpaX2MCCELeQvZ+8WxEgOnIfz7GYvsYNjLZSaRnV4G+ILY1F0QNW64S9Nvj+BwDg3ht2CrNvpwjVYlj9U3nmxE0UG5ne83LL5hhqMpm25kmL7enVgw2kQzmU2id4IKu0C/WaoDRuO2F5zE63vJbxN8AYs7338+4B4HBb6BZ6OUgg96Q15RA41/gIqxaVPxyTpDfTU5GfSLxocdYeniqqpFMtZG2n9d0u7GsQNcFkNcG3qDZm4tDo8tZbuym0a2VcF2E5hFEgXBa+XLJCfXi/77OqAEjP0x7Qdk3B43p8KG/BaioP5RsV8zBGvH1zAgyPha2rN70/tT13yrmPd5QYEfwzexjKrV4mWIuRg8NTHYSZJUaeyCwTom80VFUJXG+GYTUyv5W22aBcnoRGiCiKEYTLOkgXecdKFTHmcIAejQ9Welr0a196Kq87w5KNMCkcCGFnwBNFLmfnbpNqT6rUBxxs3X5ntX9d8HVtSYINTsGXXMZCJ7fnbWajhg/aox0FtHX21eF6qIGT8j1z+l2opU+ggwUgkhUUgCH2TfqBj+MLMVVvpgqJsPKt582caFKArIFIvO+9QupxLnEH2hz04TMTfnU6bQC6z1buVe7h+tOLnh1YPFsLQ88anib/7TTC8k9DsBTq0ASe8R2GbSEsmO9qbbMwgEaYUhOKtGeyQsSJdhSk6XxXThrWL9EnwBCXDkICMqdntAxyyM9nWsZ4bL9JHqExgWUmfWChzPFAqn3F4y896UqHTZxlq3WGypn5HHcem2Hqf3IVxKH1inhqdVtkryEiTWrI7ZdjbqnqRbl+WgtPtKOOweDlCaRs3R2qXcbNgVhleMk4IWnF8D1695AenU1LwHjOJLkCjxgNFiWAFEPH9aEXAMPLExA==",
  "Authorization": "AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXXXXXXXXX/20200401/us-east-1/appsync/aws4_request, SignedHeaders=accept;content-encoding;content-type;host;x-amz-date;x-amz-security-token, Signature=83EXAMPLEbcc1fe3ee69f75cd5ebbf4cb4f150e4f99cec869f149c5EXAMPLEdc"
}
```

**使用查詢字串請求 URL**

```
wss://api.example.com/graphql?header=eyEXAMPLEHQiOiJhcHBsaWNhdGlvbi9qc29uLCB0ZXh0L2phdmFEXAMPLEQiLCJjb250ZW50LWVuY29kaW5nIjoEXAMPLEEuMCIsImNvbnRlbnQtdHlwZSI6ImFwcGxpY2F0aW9EXAMPLE47IGNoYXJzZXQ9VVRGLTgiLCJob3N0IjoiZXhhbXBsZEXAMPLENjc4OTAwMDAuYXBwc3luYy1hcGkudXMtZWFzdC0xLmFtYEXAMPLEcy5jb20iLCJ4LWFtei1kYXRlIjoiMjAyMDA0MDFUMDAxMDEwWiIsIlgtEXAMPLElY3VyaXR5LVRva2VuIjoiQWdvSmIzSnBaMmx1WDJWakVBb2FEbUZ3TFhOdmRYUm9aV0Z6ZEMweUlrY3dSUUlnQWg5N0NsanE3d09QTDhLc3hQM1l0RHV5Yy85aEFqOFBoSjdGdmYzOFNnb0NJUURoSllKYkpsbmpQc3Bpb096dGorK3BFYWdXQ3ZlWlVqS0VuMHp5VWhCbXhpck5CUWpqLy8vLy8vLy8vLzhCRUFBYUREY3hPRGsyTkRneU56ZzFOU0lNbzFtV25wRVNXVW9ZdzRCa0txRUZTcm0zRFh1TDh3K1piVmM0SktqRFA0dlVDS05SNkxlOUM5cFpwOVBzVzBOb0Z5M3ZMQlVkQVh3dDZQSld1T1ZHOGZlWGZpRUVBKzFraGdGSy93RXR3Uis5ekY3TmFNTU1zZTA3d04yZ0cydEgwZUtNVFhuOEF3QVFYK3NNYnl0UW84aWVwUDlQWk96bFpzU0ZiL2RQNVE4aGs2WWpHVGFMMWVZY0tac1RrREFxMnVLRlE4bVlVVkE5RXRRbk5SaUZMRVk4M2FLdkcvdHFMV05uR2xTTlZ4N1NNY2ZvdmtGRHFRYW1tKzg4eTFPd3dBRVlLN3Fjb2NlWDZaN0dHY2FZdUlmR3BhWDJNQ0NFTGVRdlorOFd4RWdPbklmejdHWXZzWU5qTFpTYVJuVjRHK0lMWTFGMFFOVzY0UzlOdmorQndEZzNodDJDck52cHdqVllsajlVM25teEUwVUc1bmU4M0xMNWhocU1wbTI1a21MN2VuVmd3MmtRem1VMmlkNElLdTBDL1dhb0RSdU8yRjV6RTYzdkpieE44QVlzNzMzOCs0QjRIQmI2Qlo2T1VnZzk2UTE1UkE0MS9nSXF4YVZQeHlUcERmVFU1R2ZTTHhvY2RZZW5pcXFwRk10WkcybjlkMHU3R3NRTmNGa05jRzNxRFptNHREbzh0WmJ1eW0wYTJWY0YyRTVoRkVnWEJhK1hMSkNmWGkvNzdPcUFFalAweDdRZGszQjQzcDhLRy9CYWlvUDVSc1Y4ekJHdkgxekFneVBoYTJyTjcwL3RUMTN5cm1QZDVRWUVmd3pleGpLclY0bVdJdVJnOE5USFlTWkpVYWV5Q3dUb204MFZGVUpYRytHWVRVeXY1VzIyYUJjbm9SR2lDaUtFWVRMT2tnWGVjZEtGVEhtY0lBZWpROVdlbHIwYTE5NktxODd3NUtOTUNrY0NHRm53Qk5GTG1mbmJwTnFUNnJVQnh4czNYNW50WDlkOEhWdFNZSU5Uc0dYWE1aQ0o3Zm5iV2FqaGcvYW94MEZ0SFgyMWVGNnFJR1Q4ajF6K2wyb3BVK2dnd1Vna2hVVWdDSDJUZnFCaitNTE1WVnZwZ3FKc1BLdDU4MmNhRktBcklGSXZPKzlRdXB4TG5FSDJoejA0VE1UZm5VNmJRQzZ6MWJ1VmU3aCt0T0xuaDFZUEZzTFE4OGFuaWIvN1RUQzhrOURzQlRxMEFTZThSMkdiU0VzbU85cWJiTXdnRWFZVWhPS3RHZXlRc1NKZGhTazZYeFhUaHJXTDlFbndCQ1hEa0lDTXFkbnRBeHl5TTluV3NaNGJMOUpIcUV4Z1dVbWZXQ2h6UEZBcW4zRjR5ODk2VXFIVFp4bHEzV0d5cG41SEhjZW0ySHFmM0lWeEtIMWluaHFkVnRrcnlFaVRXckk3WmRqYnFucVJibCtXZ3RQdEtPT3dlRGxDYVJzM1IycVhjYk5nVmhsZU1rNElXbkY4RDE2OTVBZW5VMUx3SGpPSkxrQ2p4Z05GaVdBRkVQSDlhTklhcXMvWnhBPT0iLCJBdXRob3JpemF0aW9uIjoiQVdTNC1ITUFDLVNIQTI1NiBDcmVkZW50aWFsPVhYWFhYWFhYWFhYWFhYWFhYWFgvMjAxOTEwMDIvdXMtZWFzdC0xEXAMPLE5bmMvYXdzNF9yZXF1ZXN0LCBTaWduZWRIZWFkZXJzPWFjY2VwdDtjb250ZWEXAMPLE29kaW5nO2NvbnRlbnQtdHlwZTtob3EXAMPLEW16LWRhdGU7eC1hbXotc2VjdXJpdHktdG9rZW4sIFNpZ25hdHVyZT04MzE4EXAMPLEiY2MxZmUzZWU2OWY3NWNkEXAMPLE0Y2I0ZjE1MGU0Zjk5Y2VjODY5ZjE0OWM1ZDAzNDEXAMPLEn0=&payload=e30=
```

**注意**  
一個 WebSocket 連線可以有多個訂閱 （即使使用不同的身分驗證模式）。其中一種實作方式是為第一個訂閱建立 WebSocket 連線，然後在最後一個訂閱取消註冊時將其關閉。您可以等待幾秒鐘再關閉 WebSocket 連線來最佳化此作業，以防應用程式在最後一個訂閱取消註冊後立即訂閱。對於行動應用程式範例，從一個畫面變更為另一個畫面時，*在卸載*事件時，會停止訂閱，而在*掛載*事件時，則會啟動不同的訂閱。

### Lambda 授權
<a name="lambda-auth"></a>

#### Lambda 授權標頭
<a name="lambda-auth-list"></a>

**標頭內容**
+  `"Authorization": <string>`：以 傳遞的值`authorizationToken`。
+  `"host": <string>`： AWS AppSync GraphQL 端點的主機或您的自訂網域名稱。

**範例**

```
{
    "Authorization":"M0UzQzM1MkQtMkI0Ni00OTZCLUI1NkQtMUM0MTQ0QjVBRTczCkI1REEzRTIxLTk5NzItNDJENi1BQjMwLTFCNjRFNzQ2NzlCNQo=",
    "host":"example1234567890000.appsync-api.us-east-1.amazonaws.com"
}
```

**透過查詢字串的標頭**

首先，包含 `host`和 的 JSON 物件`Authorization`會轉換為字串。接下來，此字串會使用 base64 編碼進行編碼。產生的 base64 編碼字串會新增為名為 WebSocket URL `header`的查詢參數，以建立與 AWS AppSync 即時端點的連線。產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql?header=eyJBdXRob3JpemF0aW9uIjoiZXlKcmFXUWlPaUpqYkc1eGIzQTVlVzVNSzA5UVlYSXJNVEpIV0VGTFNYQmllVTVXTkhoc1FqaFBWVzlZTW5NMldsZHZQU0lzSW1Gc1p5STZJbEpUTWpVMkluMC5leUp6ZFdJaU9pSmhObU5tTWpjd055MHhOamd4TFRRMU5ESXRPV1l4T0MxbE5qWTBNVGcyTmpsa016WWlMQ0psZG1WdWRGOXBaQ0k2SW1Wa016TTVNbU5rTFdOallUTXROR00yT0MxaE5EWXlMVEpsWkdJM1pUTm1ZMkZqWmlJc0luUnZhMlZ1WDNWelpTSTZJbUZqWTJWemN5SXNJbk5qYjNCbElqb2lZWGR6TG1OdloyNXBkRzh1YzJsbmJtbHVMblZ6WlhJdVlXUnRhVzRpTENKaGRYUm9YM1JwYldVaU9qRTFOamswTlRjM01UZ3NJbWx6Y3lJNkltaDBkSEJ6T2x3dlhDOWpiMmR1YVhSdkxXbGtjQzVoY0MxemIzVjBhR1ZoYzNRdE1pNWhiV0Y2YjI1aGQzTXVZMjl0WEM5aGNDMXpiM1YwYUdWaGMzUXRNbDgzT0hZMFNWWmliVkFpTENKbGVIQWlPakUxTmprME5qRXpNakFzSW1saGRDSTZNVFUyT1RRMU56Y3lNQ3dpYW5ScElqb2lOVGd6WmpobVltTXRNemsyTVMwMFl6QTRMV0poWlRBdFl6UXlZMkl4TVRNNU5EWTVJaXdpWTJ4cFpXNTBYMmxrSWpvaU0zRmxhalZsTVhabU16ZDFOM1JvWld3MGRHOTFkREprTVd3aUxDSjFjMlZ5Ym1GdFpTSTZJbVZzYjNKNllXWmxJbjAuQjRjZEp0aDNLRk5wSjZpa1ZwN2U2RFJlZTk1VjZRaS16RUUyREpIN3NIT2wyenhZaTdmLVNtRUdvaDJBRDhlbXhRUllhakJ5ei1yRTRKaDBRT3ltTjJZcy1aSWtNcFZCVFBndS1UTVdEeU9IaERVbVVqMk9QODJ5ZVozd2xaQXRyX2dNNEx6alhVWG1JX0syeUdqdVhmWFRhYTFtdlFFQkcwbVFmVmQ3U2Z3WEItamN2NFJZVmk2ajI1cWdvdzlFdzUydWZ1clBxYUstM1dBS0czMktwVjhKNC1XZWpxOHQwYy15QTdzYjhFbkI1NTFiN1RVOTN1S1JpVlZLM0U1NU5rNUFEUG9hbV9XWUU0NWkzczVxVkFQXy1Jblc3NU5Vb09DR1RzUzhZV01mYjZlY0hZSi0xai1iekEyN3phVDlWamN0WG45YnlORlptS0xwQTJMY3h3IiwiaG9zdCI6ImV4YW1wbGUxMjM0NTY3ODkwMDAwLmFwcHN5bmMtYXBpLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tIn0=&payload=e30=
```

請務必注意，除了 base64 編碼的標頭物件之外，空的 JSON 物件 \$1\$1 也是 base64 編碼的，並包含在 WebSocket URL `payload`中做為名為 的個別查詢參數。

**透過 的標頭 `Sec-WebSocket-Protocol`**

包含 `host`和 的 JSON 物件`Authorization`會轉換為字串，然後使用 base64Url 編碼進行編碼。產生的 base64Url-encoded字串字首為 `header-`。在與 AWS AppSync 即時端點建立 WebSocket 連線時，除了 `Sec-WebSocket-Protocol`標頭`graphql-ws`中的 之外，此字首字串也會用作新的子通訊協定。

產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

`Sec-WebSocket-Protocol` 標頭包含下列值：

```
"sec-websocket-protocol" : ["graphql-ws", "header-ewogICAgImhvc3QiOiJleGFtcGxlMTIzNDU2Nzg5MDAwMC5hcHBzeW5jLWFwaS51cy1lYXN0LTEuYW1hem9uYXdzLmNvbSIsCiAgICAieC1hcGkta2V5IjoiZGEyLTEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Igp9"]
```

**透過標準 HTTP 標頭的標頭**

在此方法中，在與 AWS AppSync 即時端點建立 WebSocket 連線時，會使用標準 HTTP 標頭傳輸主機和授權資訊。產生的請求 URL 採用下列形式：

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql
```

請求標頭會包含下列項目：

```
"sec-websocket-protocol" : ["graphql-ws"]
"Authorization":"eyEXAMPLEiJjbG5xb3A5eW5MK09QYXIrMTJHWEFLSXBieU5WNHhsQjEXAMPLEnM2WldvPSIsImFsZyI6IlEXAMPLEn0.eyEXAMPLEiJhNmNmMjcwNy0xNjgxLTQ1NDItOWYxOC1lNjY0MTg2NjlkMzYiLCJldmVudF9pZCI6ImVkMzM5MmNkLWNjYTMtNGM2OC1hNDYyLTJlZGI3ZTNmY2FjZiIsInRva2VuX3VzZSI6ImFjY2VzcyIsInNjb3BlIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE1Njk0NTc3MTgsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC5hcC1zb3V0aGVhc3QtMi5hbWF6b25hd3MuY29tXC9hcC1zb3V0aGVhc3QtMl83OHY0SVZibVAiLCJleHAiOjE1Njk0NjEzMjAsImlhdCI6MTU2OTQ1NzcyMCwianRpIjoiNTgzZjhmYmMtMzk2MS00YzA4LWJhZTAtYzQyY2IxMTM5NDY5IiwiY2xpZW50X2lkIjoiM3FlajVlMXZmMzd1N3RoZWw0dG91dDJkMWwiLCJ1c2VybmFtZSI6ImVsb3EXAMPLEn0.B4EXAMPLEFNpJ6ikVp7e6DRee95V6Qi-zEE2DJH7sHOl2zxYi7f-SmEGoh2AD8emxQRYajByz-rE4Jh0QOymN2Ys-ZIkMpVBTPgu-TMWDyOHhDUmUj2OP82yeZ3wlZAtr_gM4LzjXUXmI_K2yGjuXfXTaa1mvQEBG0mQfVd7SfwXB-jcv4RYVi6j25qgow9Ew52ufurPqaK-3WAKG32KpV8J4-Wejq8t0c-yA7sb8EnB551b7TU93uKRiVVK3E55Nk5ADPoam_WYE45i3s5qVAP_-InW75NUoOCGTsS8YWMfb6ecHYJ-1j-bzA27zaT9VjctXn9byNFZmEXAMPLExw",
"host":"example1234567890000.appsync-api.us-east-1.amazonaws.com"
```

## 即時 WebSocket 操作
<a name="real-time-websocket-operation"></a>

使用 AWS AppSync 啟動成功的 WebSocket 交握後，用戶端必須傳送後續訊息，以連線至不同操作的 AWS AppSync。這些訊息需要下列資料：
+  `type`：操作類型。
+  `id`：訂閱的唯一識別符。我們建議您使用 UUID 來達到此目的。
+  `payload`：相關聯的承載，取決於操作類型。

`type` 欄位是唯一的必要欄位； `id`和 `payload` 欄位是選用的。

### 事件順序
<a name="sequence-of-events"></a>

若要成功啟動、建立、註冊和處理訂閱請求，用戶端必須逐步執行下列順序：

1. 初始化連線 (`connection_init`)

1. 連線確認 (`connection_ack`)

1. 訂閱註冊 (`start`)

1. 訂閱確認 (`start_ack`)

1. 正在處理訂閱 (`data`)

1. 取消註冊訂閱 (`stop`)

## 連線初始化訊息
<a name="connection-init-message"></a>

（選用） 成功交握後，用戶端可以傳送訊息`connection_init`，開始與 AWS AppSync 即時端點通訊。訊息是透過將 JSON 物件字串化來取得的字串，如下所示：

```
{ "type": "connection_init" }
```

## 連線確認訊息
<a name="connection-acknowledge-message"></a>

傳送 `connection_init` 訊息後，用戶端必須等待 `connection_ack` 訊息。接收前傳送的所有訊息`connection_ack`都會遭到忽略。該訊息應該如下所示：

```
{
  "type": "connection_ack",
  "payload": {
    // Time in milliseconds waiting for ka message before the client should terminate the WebSocket connection
    "connectionTimeoutMs": 300000
  }
}
```

## 保持啟用訊息
<a name="keep-alive-message"></a>

除了連線確認訊息之外，用戶端還會定期接收保持連線訊息。如果用戶端未在連線逾時期間內收到持續連線訊息，用戶端應關閉連線。 AWS AppSync 會持續傳送這些訊息和服務已註冊的訂閱，直到其自動關閉連線為止 (24 小時後）。保持連線訊息是活動訊號，不需要用戶端來確認它們。

```
{ "type": "ka" }
```

## 訂閱註冊訊息
<a name="subscription-registration-message"></a>

用戶端收到`connection_ack`訊息後，用戶端可以將訂閱註冊訊息傳送至 AWS AppSync。此類型的訊息是字串化的 JSON 物件，其中包含下列欄位：
+  `"id": <string>`：訂閱的 ID。此 ID 對於每個訂閱都必須是唯一的，否則伺服器會傳回錯誤，指出訂閱 ID 重複。
+  `"type": "start"`：常數 `<string>` 參數。
+  `"payload": <Object>`：包含訂閱相關資訊的物件。
  +  `"data": <string>`：包含 GraphQL 查詢和變數的字串化 JSON 物件。
    +  `"query": <string>`：GraphQL 操作。
    +  `"variables": <Object>`：包含查詢變數的物件。
  +  `"extensions": <Object>`：包含授權物件的物件。
+  `"authorization": <Object>`：包含授權所需欄位的物件。

### 訂閱註冊的授權物件
<a name="authorization-object-for-subscription-registration"></a>

[以 AWS AppSync API 授權模式為基礎的標頭參數格式](#header-parameter-format-based-on-appsync-api-authorization-mode) 區段中的相同規則適用於授權物件。唯一的例外是 IAM，其中 SigV4 簽章資訊略有不同。如需詳細資訊，請參閱 IAM 範例。

使用 Amazon Cognito 使用者集區的範例：

```
{
  "id": "ee849ef0-cf23-4cb8-9fcb-152ae4fd1e69",
  "payload": {
    "data": "{\"query\":\"subscription onCreateMessage {\\n onCreateMessage {\\n __typename\\n message\\n }\\n }\",\"variables\":{}}",
      "extensions": {
        "authorization": {
          "Authorization": "eyEXAMPLEiJjbG5xb3A5eW5MK09QYXIrMTJEXAMPLEBieU5WNHhsQjhPVW9YMnM2WldvPSIsImFsZyI6IlEXAMPLEn0.eyJzdWIiOiJhNmNmMjcwNy0xNjgxLTQ1NDItEXAMPLENjY0MTg2NjlkMzYiLCJldmVudF9pZCI6ImU3YWVmMzEyLWUEXAMPLEY0Zi04YjlhLTRjMWY5M2Q5ZTQ2OCIsInRva2VuX3VzZSI6ImFjY2VzcyIsIEXAMPLEIjoiYXdzLmNvZ25pdG8uc2lnbmluLnVzZXIuYWRtaW4iLCJhdXRoX3RpbWUiOjE1Njk2MTgzMzgsImlzcyI6Imh0dEXAMPLEXC9jb2duaXRvLWlkcC5hcC1zb3V0aGVhc3QtMi5hbWF6b25hd3MuY29tXC9hcC1zbEXAMPLEc3QtMl83OHY0SVZibVAiLCJleHAiOjE1NzAyNTQ3NTUsImlhdCI6MTU3MDI1MTE1NSwianRpIjoiMmIEXAMPLEktZTVkMi00ZDhkLWJiYjItNjA0YWI4MDEwOTg3IiwiY2xpZW50X2lkIjoiM3FlajVlMXZmMzd1EXAMPLE0dG91dDJkMWwiLCJ1c2VybmFtZSI6ImVsb3J6YWZlIn0.CT-qTCtrYeboUJ4luRSTPXaNewNeEXAMPLE14C6sfg05tO0fOMpiUwj9k19gtNCCMqoSsjtQoUweFnH4JYa5EXAMPLEVxOyQEQ4G7jQrt5Ks6STn53vuseR3zRW9snWgwz7t3ZmQU-RWvW7yQU3sNQRLEXAMPLEcd0yufBiCYs3dfQxTTdvR1B6Wz6CD78lfNeKqfzzUn2beMoup2h6EXAMPLE4ow8cUPUPvG0DzRtHNMbWskjPanu7OuoZ8iFO_Eot9kTtAlVKYoNbWkZhkD8dxutyoU4RSH5JoLAnrGF5c8iKgv0B2dfEXAMPLEIihxaZVJ9w9w48S4EXAMPLEcA",
          "host": "example1234567890000.appsync-api.us-east-1.amazonaws.com"
         }
      }
  },
  "type": "start"
}
```

使用 IAM 的範例：

```
{
  "id": "eEXAMPLE-cf23-1234-5678-152EXAMPLE69",
  "payload": {
    "data": "{\"query\":\"subscription onCreateMessage {\\n onCreateMessage {\\n __typename\\n message\\n }\\n }\",\"variables\":{}}",
    "extensions": {
      "authorization": {
        "accept": "application/json, text/javascript",
        "content-type": "application/json; charset=UTF-8",
        "X-Amz-Security-Token": "AgEXAMPLEZ2luX2VjEAoaDmFwLXNvdXRoZWFEXAMPLEcwRQIgAh97Cljq7wOPL8KsxP3YtDuyc/9hAj8PhJ7Fvf38SgoCIQDhJEXAMPLEPspioOztj++pEagWCveZUjKEn0zyUhBEXAMPLEjj//////////8BEXAMPLExODk2NDgyNzg1NSIMo1mWnpESWUoYw4BkKqEFSrm3DXuL8w+ZbVc4JKjDP4vUCKNR6Le9C9pZp9PsW0NoFy3vLBUdAXEXAMPLEOVG8feXfiEEA+1khgFK/wEtwR+9zF7NaMMMse07wN2gG2tH0eKMEXAMPLEQX+sMbytQo8iepP9PZOzlZsSFb/dP5Q8hk6YEXAMPLEYcKZsTkDAq2uKFQ8mYUVA9EtQnNRiFLEY83aKvG/tqLWNnGlSNVx7SMcfovkFDqQamm+88y1OwwAEYK7qcoceX6Z7GGcaYuIfGpaX2MCCELeQvZ+8WxEgOnIfz7GYvsYNjLZSaRnV4G+ILY1F0QNW64S9Nvj+BwDg3ht2CrNvpwjVYlj9U3nmxE0UG5ne83LL5hhqMpm25kmL7enVgw2kQzmU2id4IKu0C/WaoDRuO2F5zE63vJbxN8AYs7338+4B4HBb6BZ6OUgg96Q15RA41/gIqxaVPxyTpDfTU5GfSLxocdYeniqqpFMtZG2n9d0u7GsQNcFkNcG3qDZm4tDo8tZbuym0a2VcF2E5hFEgXBa+XLJCfXi/77OqAEjP0x7Qdk3B43p8KG/BaioP5RsV8zBGvH1zAgyPha2rN70/tT13yrmPd5QYEfwzexjKrV4mWIuRg8NTHYSZJUaeyCwTom80VFUJXG+GYTUyv5W22aBcnoRGiCiKEYTLOkgXecdKFTHmcIAejQ9Welr0a196Kq87w5KNMCkcCGFnwBNFLmfnbpNqT6rUBxxs3X5ntX9d8HVtSYINTsGXXMZCJ7fnbWajhg/aox0FtHX21eF6qIGT8j1z+l2opU+ggwUgkhUUgCH2TfqBj+MLMVVvpgqJsPKt582caFKArIFIvO+9QupxLnEH2hz04TMTfnU6bQC6z1buVe7h+tOLnh1YPFsLQ88anib/7TTC8k9DsBTq0ASe8R2GbSEsmO9qbbMwgEaYUhOKtGeyQsSJdhSk6XxXThrWL9EnwBCXDkICMqdntAxyyM9nWsZ4bL9JHqExgWUmfWChzPFAqn3F4y896UqHTZxlq3WGypn5HHcem2Hqf3IVxKH1inhqdVtkryEiTWrI7ZdjbqnqRbl+WgtPtKOOweDlCaRs3R2qXcbNgVhleMk4IWnF8D1695AenU1LwHjOJLkCjxgNFiWAFEPH9aEXAMPLExA==",
        "Authorization": "AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXXXXXXXXXX/20200401/us-east-1/appsync/aws4_request, SignedHeaders=accept;content-encoding;content-type;host;x-amz-date;x-amz-security-token, Signature=b90131a61a7c4318e1c35ead5dbfdeb46339a7585bbdbeceeaff51f4022eb1fd",
        "content-encoding": "amz-1.0",
        "host": "example1234567890000.appsync-api.us-east-1.amazonaws.com",
        "x-amz-date": "20200401T001010Z"
      }
    }
  },
  "type": "start"
}
```

使用自訂網域名稱的範例：

```
{
  "id": "key-cf23-4cb8-9fcb-152ae4fd1e69",
  "payload": {
    "data": "{\"query\":\"subscription onCreateMessage {\\n onCreateMessage {\\n __typename\\n message\\n }\\n }\",\"variables\":{}}",
      "extensions": {
        "authorization": {
          "x-api-key": "da2-12345678901234567890123456",
          "host": "api.example.com"
         }
      }
  },
  "type": "start"
}
```

SigV4 簽章不需要`/connect`附加至 URL，而且 JSON 字串化 GraphQL 操作會取代 `data`。以下是 SigV4 簽章請求的範例：

```
{
  url: "https://example1234567890000.appsync-api.us-east-1.amazonaws.com/graphql",
  data: "{\"query\":\"subscription onCreateMessage {\\n onCreateMessage {\\n __typename\\n message\\n }\\n }\",\"variables\":{}}",
  method: "POST",
  headers: {
    "accept": "application/json, text/javascript",
    "content-encoding": "amz-1.0",
    "content-type": "application/json; charset=UTF-8",
  }
}
```

## 訂閱確認訊息
<a name="subscription-acknowledge-message"></a>

傳送訂閱開始訊息後，用戶端應該等待 AWS AppSync 傳送訊息`start_ack`。`start_ack` 訊息指出訂閱成功。

訂閱確認範例：

```
{
  "type": "start_ack",
  "id": "eEXAMPLE-cf23-1234-5678-152EXAMPLE69"
}
```

## 錯誤訊息
<a name="error-message"></a>

如果連線初始化或訂閱註冊失敗，或訂閱從伺服器結束，伺服器會傳送錯誤訊息給用戶端。如果在連線初始化期間發生錯誤，伺服器將會關閉連線。
+  `"type": "error"`：常數 `<string>` 參數。
+  `"id": <string>`：相應已註冊訂閱的 ID，如果相關的話。
+  `"payload" <Object>`：包含對應錯誤資訊的物件。

範例：

```
{
  "type": "error",
  "payload": {
    "errors": [
      {
        "errorType": "LimitExceededError",
        "message": "Rate limit exceeded"
      }
    ]
  }
}
```

## 處理資料訊息
<a name="processing-data-messages"></a>

當用戶端提交變動時， AWS AppSync 會識別對其感興趣的所有訂閱者，並使用訂閱操作中對應的訂閱傳送訊息`"type":"data"`給每個`id``"start"`訂閱者。預期用戶端會追蹤`id`其傳送的訂閱，以便在接收資料訊息時，用戶端可以比對其與對應的訂閱。
+  `"type": "data"`：常數 `<string>` 參數。
+  `"id": <string>`：對應已註冊訂閱的 ID。
+  `"payload" <Object>`：包含訂閱資訊的物件。

範例：

```
{
  "type": "data",
  "id": "ee849ef0-cf23-4cb8-9fcb-152ae4fd1e69",
  "payload": {
    "data": {
      "onCreateMessage": {
        "__typename": "Message",
        "message": "test"
      }
    }
  }
}
```

## 訂閱取消註冊訊息
<a name="subscription-unregistration-message"></a>

當應用程式想要停止監聽訂閱事件時，用戶端應該使用下列字串化 JSON 物件傳送訊息：
+  `"type": "stop"`：常數 `<string>` 參數。
+  `"id": <string>`：要取消註冊的訂閱 ID。

範例：

```
{
  "type":"stop",
  "id":"ee849ef0-cf23-4cb8-9fcb-152ae4fd1e69"
}
```

AWS AppSync 會使用下列字串化 JSON 物件傳回確認訊息：
+  `"type": "complete"`：常數 `<string>` 參數。
+  `"id": <string>`：未註冊訂閱的 ID。

用戶端收到確認訊息後，就不會再收到此特定訂閱的訊息。

範例：

```
{
  "type":"complete",
  "id":"eEXAMPLE-cf23-1234-5678-152EXAMPLE69"
}
```

## 斷開 WebSocket 的連線
<a name="disconnecting-the-websocket"></a>

在中斷連線之前，為了避免資料遺失，用戶端應具有必要的邏輯，以檢查目前沒有透過 WebSocket 連線進行的操作。從 WebSocket 中斷連線之前，所有訂閱都應該取消註冊。

# 在 中合併 APIs AWS AppSync
<a name="merged-api"></a>

隨著 GraphQL 的使用在組織內擴展，可能會出現 API ease-of-use API 開發速度之間的權衡。一方面，組織採用 AWS AppSync 和 GraphQL 來簡化應用程式開發。這可讓開發人員靈活地使用 API，以單一網路呼叫安全地存取、操作和結合來自一或多個資料網域的資料。另一方面，組織內負責將不同資料網域合併到單一 GraphQL API 端點的團隊，可能希望能夠建立、管理和部署彼此獨立的 API 更新。這會增加其開發速度。

為了解決這種壓力， AWS AppSync 合併 APIs 功能允許來自不同資料網域的團隊獨立建立和部署 AWS AppSync APIs （例如 GraphQL 結構描述、解析程式、資料來源和函數），然後可以合併為單一合併 API。這可讓組織維持簡單易用的跨網域 API，以及讓不同團隊能夠快速獨立進行 API 更新的方式。

下圖顯示合併的 API 工作流程：

![\[顯示合併 API 工作流程的圖表，其中多個來源 APIs 會合併為單一合併 API 端點\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/merged-api-workflow.png)


使用合併 APIs，組織可以將多個獨立來源 AWS AppSync APIs的資源匯入單一 AWS AppSync 合併 API 端點。若要這樣做， AWS AppSync 可讓您建立 AWS AppSync APIs 清單，然後將與來源 APIs 相關聯的所有中繼資料，包括結構描述、類型、資料來源、解析程式和函數，合併到新的 AWS AppSync 合併 API。

在合併期間，可能會因為來源 API 資料內容中的不一致而發生合併衝突，例如在合併多個結構描述時類型命名衝突。對於來源 APIs衝突的簡單使用案例，不需要修改來源 API 結構描述。產生的合併 API 只會從原始 AWS AppSync APIs 匯入所有類型、解析程式、資料來源和函數。對於發生衝突的複雜使用案例，使用者/團隊必須透過各種方式解決衝突。 為使用者 AWS AppSync 提供數種工具和範例，可以減少合併衝突。

在 中設定的後續合併 AWS AppSync 會將來源 APIs中所做的變更傳播到相關聯的合併 API。

## 合併 APIs和聯合
<a name="merged-api-federation"></a>

GraphQL 社群中有許多解決方案和模式，可用於合併 GraphQL 結構描述並透過共用圖形實現團隊協作。 AWS AppSync 合併 APIs採用*建置時間*方法來建構結構描述合成，其中來源 APIs會合併為單獨的合併 API。另一種方法是將多個來源 APIs或子圖形的*執行時間*路由器分層。在此方法中，路由器會接收請求、參考其維護為中繼資料的合併結構描述、建構請求計劃，然後將請求元素分佈至其基礎子圖/伺服器。下表將 AWS AppSync 合併 API 建置時間方法與以路由器為基礎的執行時間方法與 GraphQL 結構描述合成進行比較：


|  |  |  | 
| --- |--- |--- |
| Feature | AppSync Merged API | Router-based solutions | 
| Sub-graphs managed independently | Yes | Yes | 
| Sub-graphs addressable independently | Yes | Yes | 
| Automated schema composition | Yes | Yes | 
| Automated conflict detection | Yes | Yes | 
| Conflict resolution via schema directives | Yes | Yes | 
| Supported sub-graph servers | AWS AppSync\$1 | Varies | 
| Network complexity | Single, merged API means no extra network hops. | Multi-layer architecture requires query planning and delegation, sub-query parsing and serialization/deserialization, and reference resolvers in sub-graphs to perform joins. | 
| Observability support | Built-in monitoring, logging, and tracing. A single, Merged API server means simplified debugging. | Build-your-own observability across router and all associated sub-graph servers. Complex debugging across distributed system. | 
| Authorization support | Built in support for multiple authorization modes. | Build-your-own authorization rules. | 
| Cross account security | Built-in support for cross-AWS cloud account associations. | Build-your-own security model. | 
| Subscriptions support | Yes | No | 

\$1 AWS AppSync 合併 APIs只能與 AWS AppSync 來源 APIs建立關聯。如果您需要跨 AWS AppSync 和非AWS AppSync 子圖形結構描述合成的支援，您可以將一或多個 AWS AppSync GraphQL 和/或合併 APIs 連接到以路由器為基礎的解決方案。例如，請參閱參考部落格，以使用具有 Apollo Federation v2：[Apollo GraphQL Federation AWS AppSync](https://aws.amazon.com/blogs/mobile/federation-appsync-subgraph/) 的路由器型架構將 AWS AppSync APIs 新增為子圖。

**Topics**
+ [合併 APIs和聯合](#merged-api-federation)
+ [合併 API 衝突解決](#merged-api-conflict-resolution)
+ [設定結構描述](#configuring-schemas-merged-api)
+ [設定授權模式](#configuring-authorization-merged-api)
+ [設定執行角色](#execution-roles-merged-api)
+ [使用 設定跨帳戶合併 APIs AWS RAM](#cross-account-merged-api)
+ [合併](#merges)
+ [合併 APIs的其他支援](#merge-api-additional-support)
+ [合併 API 限制](#merged-api-limits)
+ [合併 API 考量事項](#merged-api-considerations)
+ [建立合併 APIs](#creating-merged-api)

## 合併 API 衝突解決
<a name="merged-api-conflict-resolution"></a>

發生合併衝突時， AWS AppSync 會提供使用者數種工具和範例 （以協助疑難排解問題）。

### 合併 API 結構描述指令
<a name="merged-api-schema-directive"></a>

 AWS AppSync 引進數個 GraphQL 指令，可用於減少或解決來源 APIs之間的衝突：
+ *@canonical*：此指令會設定具有類似名稱和資料的類型/欄位優先順序。如果兩個或多個來源 APIs 具有相同的 GraphQL 類型或欄位，則其中一個 APIs 可以將其類型或欄位標註為*正式*，這將在合併期間優先處理。合併時，會忽略其他來源 APIs 中未以此指令標註的衝突類型/欄位。
+ *@hidden*：此指令會封裝特定類型/欄位，以將其從合併程序中移除。團隊可能想要移除或隱藏來源 API 中的特定類型或操作，因此只有內部用戶端可以存取特定類型資料。附加此指令後，類型或欄位不會合併到合併 API。
+ *@renamed*：此指令會變更類型/欄位的名稱，以減少命名衝突。在某些情況下，不同的 APIs具有相同的類型或欄位名稱。不過，它們都需要在合併的結構描述中可用。將它們全部包含在合併 API 中的簡單方法是將欄位重新命名為類似但不同的欄位。

若要顯示公用程式結構描述指令，請考慮下列範例：

在此範例中，假設我們想要合併兩個來源 APIs。我們獲得兩個結構描述來建立和擷取文章 （例如評論區段或社交媒體文章）。假設類型和欄位非常類似，在合併操作期間發生衝突的機率很高。以下程式碼片段顯示每個結構描述的類型和欄位。

第一個檔案名為 *Source1.graphql*，是一個 GraphQL 結構描述，允許使用者`Posts`使用 `putPost` 變動建立 。每個 都`Post`包含標題和 ID。ID 用於參考 `User`、 或張貼者的資訊 （電子郵件和地址），以及 `Message`或承載 （內容）。`User` 類型會以 *@canonical* 標籤標註。

```
# This snippet represents a file called Source1.graphql

type Mutation {
    putPost(id: ID!, title: String!): Post
}

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

type Message {
   id: ID!
   content: String
}

type User @canonical {
   id: ID!
   email: String!
   address: String!
}

type Query {
    singlePost(id: ID!): Post
    getMessage(id: ID!): Message
}
```

第二個檔案名為 *Source2.graphql*，是一個 GraphQL 結構描述，其作用與 *Source1.graphql* 非常相似。不過請注意，每種類型的欄位都不同。合併這兩個結構描述時，會因為這些差異而發生合併衝突。

另請注意 *Source2.graphql* 如何也包含數個指令來減少這些衝突。`Post` 類型會以 *@hidden* 標籤標註，以在合併操作期間混淆自己。`Message` 類型會以 *@renamed* 標籤標註，以便在命名與其他`Message`類型衝突`ChatMessage`時將類型名稱修改為 。

```
# This snippet represents a file called Source2.graphql

type Post @hidden  {
    id: ID!
    title: String!
    internalSecret: String!
}

type Message @renamed(to: "ChatMessage") {
   id: ID!
   chatId: ID!
   from: User!
   to: User!
}

# Stub user so that we can link the canonical definition from Source1
type User {
   id: ID!
}

type Query {
    getPost(id: ID!): Post
    getMessage(id: ID!): Message @renamed(to: "getChatMessage")
}
```

合併發生時，結果會產生 `MergedSchema.graphql` 檔案：

```
# This snippet represents a file called MergedSchema.graphql

type Mutation {
    putPost(id: ID!, title: String!): Post
}

# Post from Source2 was hidden so only uses the Source1 definition. 
type Post {
    id: ID!
    title: String!
}

# Renamed from Message to resolve the conflict
type ChatMessage {
   id: ID!
   chatId: ID!
   from: User!
   to: User!
}

type Message {
   id: ID!
   content: String
}

# Canonical definition from Source1
type User {
   id: ID!
   email: String!
   address: String!
}

type Query {
    singlePost(id: ID!): Post
    getMessage(id: ID!): Message
    
    # Renamed from getMessage
    getChatMessage(id: ID!): ChatMessage
}
```

合併中發生了幾件事：
+ 由於 *@canonical* 註釋，*Source1.graphql* 的`User`類型優先於 `User` *Source2.graphql 的 。*
+ Source1.graphql 的`Message`類型包含在合併中。 *Source1* 不過，`Message`來自 *Source2.graphql 的 *有命名衝突。由於其 *@renamed* 註釋，它也包含在合併中，但具有替代名稱 `ChatMessage`。
+ 包含 *Source1.graphql* 的`Post`類型，但不包含 *Source2.graphql *的`Post`類型。通常，此類型會發生衝突，但由於 Source2.graphql 的`Post`類型具有 *@hidden* 註釋，因此其資料會混淆，且不包含在合併中。 *Source2* 這不會造成任何衝突。
+ 已更新 `Query`類型，以包含兩個檔案的內容。不過，`GetChatMessage`由於 指令，一個`GetMessage`查詢已重新命名為 。這解決了兩個具有相同名稱的查詢之間的命名衝突。

也有未將任何指令新增至衝突類型的情況。在這裡，合併類型將包含該類型所有來源定義中所有欄位的聯集。例如，請考量下列範例：

此結構描述稱為 *Source1.graphql*，允許建立和擷取 `Posts`。組態類似於先前的範例，但資訊較少。

```
# This snippet represents a file called Source1.graphql

type Mutation {
    putPost(id: ID!, title: String!): Post
}

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

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

此結構描述稱為 *Source2.graphql*，允許建立和擷取 `Reviews`（例如電影評分或餐廳評論）。 `Reviews` 與相同 ID 值`Post`的 相關聯。它們一起包含完整檢閱文章的標題、文章 ID 和承載訊息。

合併時，這兩種`Post`類型之間會發生衝突。由於沒有註釋可解決此問題，預設行為是對衝突的類型執行聯集操作。

```
# This snippet represents a file called Source2.graphql

type Mutation {
    putReview(id: ID!, postId: ID!, comment: String!): Review
}

type Post  {
    id: ID!
    reviews: [Review]
}

type Review {
   id: ID!
   postId: ID!
   comment: String!
}

type Query {
    getReview(id: ID!): Review
}
```

合併發生時，結果會產生 `MergedSchema.graphql` 檔案：

```
# This snippet represents a file called MergedSchema.graphql

type Mutation {
    putReview(id: ID!, postId: ID!, comment: String!): Review
    putPost(id: ID!, title: String!): Post
}

type Post  {
    id: ID!
    title: String!
    reviews: [Review]
}

type Review {
   id: ID!
   postId: ID!
   comment: String!
}

type Query {
    getPost(id: ID!): Post
    getReview(id: ID!): Review
}
```

合併中發生了幾件事：
+ `Mutation` 類型沒有衝突且已合併。
+ `Post` 類型欄位是透過聯集操作合併。請注意兩者之間的聯集如何產生單一 `id`、 `title`和單一 `reviews`。
+ `Review` 類型沒有衝突且已合併。
+ `Query` 類型沒有衝突且已合併。

### 在共用類型上管理解析程式
<a name="resolvers-shared-types-merged-api"></a>

在上述範例中，請考慮 *Source1.graphql* 已在 上設定單位解析程式的情況`Query.getPost`，該解析程式使用名為 的 DynamoDB 資料來源`PostDatasource`。此解析程式會傳回 `id`和 `title` `Post`類型的 。現在，請考慮 *Source2.graphql* 已在 上設定管道解析程式`Post.reviews`，其會執行兩個 函數。 `Function1` 已連接`None`資料來源以執行自訂授權檢查。 `Function2` 已連接 DynamoDB 資料來源以查詢`reviews`資料表。

```
query GetPostQuery {
    getPost(id: "1") {
        id,
        title,
        reviews
    }
}
```

當用戶端對合併 API 端點執行上述查詢時， AWS AppSync 服務會先`Query.getPost`從 執行 的單位解析程式`Source1`，呼叫 `PostDatasource`並從 DynamoDB 傳回資料。然後，它會執行`Post.reviews`管道解析程式，其中 會`Function1`執行自訂授權邏輯，並在 `id` 中找到的 後`Function2`傳回檢閱`$context.source`。服務會將請求處理為單一 GraphQL 執行，而此簡單請求只需要單一請求字符。

### 管理共用類型的解析程式衝突
<a name="resolver-conflict-shared-type-merged-api"></a>

在下列情況下，我們也會在 上實作解析程式，`Query.getPost`以便一次提供超過 中欄位解析程式的多個欄位`Source2`。*Source1.graphql* 可能如下所示：

```
# This snippet represents a file called Source1.graphql

type Post  {
    id: ID!
    title: String!
    date: AWSDateTime!
}

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

*Source2.graphql* 可能如下所示：

```
# This snippet represents a file called Source2.graphql

type Post  {
  id: ID!
  content: String!
  contentHash: String! 
  author: String! 
}

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

嘗試合併這兩個結構描述會產生合併錯誤，因為 AWS AppSync 合併 APIs 不允許多個來源解析程式連接到相同的欄位。若要解決此衝突，您可以實作需要 *Source2.graphql* 新增個別類型的欄位解析程式模式，以定義其從`Post`類型擁有的欄位。在下列範例中，我們新增名為 的類型`PostInfo`，其中包含由 *Source2.graphql* 解析的內容和作者欄位。*Source1.graphql* 將實作連接至 的解析程式`Query.getPost`，而 *Source2.graphql* 現在會將解析程式連接至 `Post.postInfo`，以確保所有資料都能成功擷取：

```
type Post  {
  id: ID!
  postInfo: PostInfo
}

type PostInfo {
   content: String!
   contentHash: String!
   author: String!
}

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

雖然解決這類衝突需要重寫來源 API 結構描述，而且可能還需要用戶端變更其查詢，但此方法的優點是合併解析程式的擁有權在來源團隊之間仍然很明確。

## 設定結構描述
<a name="configuring-schemas-merged-api"></a>

兩方負責設定結構描述以建立合併 API：
+ **合併 API 擁有者** - 合併 API 擁有者必須設定合併 API 的授權邏輯和進階設定，例如記錄、追蹤、快取和 WAF 支援。
+ **關聯的來源 API 擁有者** - 關聯的 API 擁有者必須設定組成合併 API 的結構描述、解析程式和資料來源。

由於合併 API 的結構描述是從相關聯來源 APIs，因此僅供**讀取**。這表示必須在來源 APIs 中啟動結構描述的變更。在 AWS AppSync 主控台中，您可以使用結構描述視窗上方的下拉式清單，在合併結構描述與合併 APIs 中包含的來源 API 的個別**結構描述**之間切換。

## 設定授權模式
<a name="configuring-authorization-merged-api"></a>

有多種授權模式可用於保護您的合併 API。若要進一步了解 中的授權模式 AWS AppSync，請參閱[授權和身分驗證](https://docs.aws.amazon.com/appsync/latest/devguide/security-authz.html)。

下列授權模式可用於合併 APIs：
+  **API 金鑰**：最簡單的授權策略。所有請求都必須在`x-api-key`請求標頭下包含 API 金鑰。過期的 API 金鑰會在過期日期後保留 60 天。
+  **AWS Identity and Access Management (IAM)**：IAM 授權策略會授權所有**已簽署 sigv4** 的請求。 AWS 
+  **Amazon Cognito 使用者集**區：透過 Amazon Cognito 使用者集區授權您的使用者，以實現更精細的控制。
+  **AWS Lambda 授權方**：一種無伺服器函數，可讓您使用自訂邏輯來驗證和授權對 AWS AppSync API 的存取。
+ **OpenID Connect**：此授權類型會強制執行 OIDC 相容服務提供的 OpenID Connect (OIDC) 權杖。您的應用程式可以運用由 OIDC 提供者定義的使用者與權限來控制存取權限。

合併 API 的授權模式是由合併 API 擁有者設定。在合併操作時，合併 API 必須包含在來源 API 上設定的主要授權模式，做為其本身的主要授權模式或次要授權模式。否則，它會不相容，合併操作會失敗並產生衝突。在來源 APIs 中使用多重驗證指令時，合併程序能夠將這些指令自動合併到統一的端點。如果來源 API 的主要授權模式不符合合併 API 的主要授權模式，則會自動新增這些身分驗證指令，以確保來源 API 中類型的授權模式一致。

## 設定執行角色
<a name="execution-roles-merged-api"></a>

建立合併 API 時，您需要定義服務角色。 AWS 服務角色是 AWS 服務用來代表您執行任務的 AWS Identity and Access Management (IAM) 角色。

在這種情況下，您的合併 API 必須執行解析程式，才能從來源 APIs 中設定的資料來源存取資料。此 所需的服務角色是 `mergedApiExecutionRole`，而且必須具有明確存取權，才能透過 IAM 許可在合併 APIs 中包含的來源 API `appsync:SourceGraphQL` 上執行請求。在執行 GraphQL 請求期間， AWS AppSync 服務將擔任此服務角色，並授權該角色執行`appsync:SourceGraphQL`動作。

AWS AppSync 支援允許或拒絕請求中特定最上層欄位的此許可，例如 IAM 授權模式對 IAM APIs 的運作方式。對於non-top-level欄位， AWS AppSync 會要求您定義來源 API ARN 本身的許可。為了限制對合併 API 中特定non-top-level欄位的存取，我們建議您在 Lambda 中實作自訂邏輯，或使用 *@hidden* 指令從合併 API 隱藏來源 API 欄位。如果您想要允許角色在來源 API 內執行所有資料操作，您可以新增以下政策。請注意，第一個資源項目允許存取所有最上層欄位，第二個項目涵蓋在來源 API 資源本身上授權的子解析程式：

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

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [{
        "Effect": "Allow", 
        "Action": [ "appsync:SourceGraphQL"], 
        "Resource": [ 
            "arn:aws:appsync:us-west-2:123456789012:apis/YourSourceGraphQLApiId/*", 
            "arn:aws:appsync:us-west-2:123456789012:apis/YourSourceGraphQLApiId"] 
    }] 
}
```

------

如果您想要將存取權限制在特定最上層欄位，您可以使用如下所示的政策：

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

****  

```
{
    "Version":"2012-10-17",		 	 	 
    "Statement": [{
        "Effect": "Allow", 
        "Action": [ "appsync:SourceGraphQL"], 
        "Resource": [ 
            "arn:aws:appsync:us-west-2:123456789012:apis/YourSourceGraphQLApiId/types/Query/fields/<Field-1>",
            "arn:aws:appsync:us-west-2:123456789012:apis/YourSourceGraphQLApiId"] 
    }] 
}
```

------

您也可以使用 AWS AppSync 主控台 API 建立精靈來產生服務角色，以允許合併 API 存取在與合併 API 位於相同帳戶中APIs 中設定的資源。如果您的來源 APIs 與合併的 API 不在同一個帳戶中，您必須先使用 AWS Resource Access Manager () 共用資源AWS RAM。

## 使用 設定跨帳戶合併 APIs AWS RAM
<a name="cross-account-merged-api"></a>

建立合併 API 時，您可以選擇將來源 APIs 與透過 AWS Resource Access Manager () 共用的其他帳戶建立關聯AWS RAM。 AWS RAM 可協助您跨 AWS 帳戶、組織或組織單位 (OUs) 以及 IAM 角色和使用者安全地共用資源。

AWS AppSync 與 整合， AWS RAM 以支援從單一合併 APIs 跨多個帳戶設定和存取來源 API。 AWS RAM 可讓您建立資源共用或資源容器，以及將針對每個資源共用的許可集。您可以將 AWS AppSync APIs新增至資源共享 AWS RAM。在資源共用中， AWS AppSync 提供三種不同的許可集，可與 RAM 中的 AWS AppSync API 相關聯：

1. `AWSRAMPermissionAppSyncSourceApiOperationAccess`： AWS RAM 如果未指定其他許可，則在 中共用 AWS AppSync API 時新增的預設許可集。此許可集用於與合併 AWS AppSync API 擁有者共用來源 API。此許可集包含來源 API `appsync:AssociateMergedGraphqlApi` 上的 許可，以及在執行時間存取來源 API 資源所需的`appsync:SourceGraphQL`許可。

1. `AWSRAMPermissionAppSyncMergedApiOperationAccess`：與來源 API 擁有者共用合併 API 時，應設定此許可集。此許可集可讓來源 API 設定合併 API，包括將目標主體擁有的任何來源 APIs 與合併 API 建立關聯，以及讀取和更新合併 API 的來源 API 關聯。

1. `AWSRAMPermissionAppSyncAllowSourceGraphQLAccess`：此許可集允許 `appsync:SourceGraphQL`許可與 AWS AppSync API 搭配使用。它旨在用於與合併 API 擁有者共用來源 API。與來源 API 操作存取的預設許可集相反，此許可集僅包含執行時間許可 `appsync:SourceGraphQL`。如果使用者選擇將合併 API 操作存取權分享給來源 API 擁有者，他們也需要從來源 API 分享此許可給合併 API 擁有者，才能透過合併 API 端點取得執行時間存取權。

AWS AppSync 也支援客戶受管許可。當其中一個提供的 AWS受管許可無法運作時，您可以建立自己的客戶受管許可。客戶受管許可是您撰寫和維護的受管許可，透過精確指定可在使用 共用資源的條件下執行哪些動作 AWS RAM。 AWS AppSync 可讓您在建立自己的許可時從下列動作中進行選擇：

1. `appsync:AssociateSourceGraphqlApi`

1. `appsync:AssociateMergedGraphqlApi`

1. `appsync:GetSourceApiAssociation`

1. `appsync:UpdateSourceApiAssociation`

1. `appsync:StartSchemaMerge`

1. `appsync:ListTypesByAssociation`

1. `appsync:SourceGraphQL`

一旦您在 中正確共用來源 API 或合併 API， AWS RAM 並且在必要時已接受資源共用邀請，當您在合併 API 上建立或更新來源 API 關聯時，就會在 AWS AppSync 主控台中顯示。您也可以透過呼叫 提供`ListGraphqlApis`的操作 AWS AppSync 並使用`OTHER_ACCOUNTS`擁有者篩選條件，列出使用 AWS RAM 與您的帳戶共用的所有 AWS AppSync APIs，無論許可設定為何。

**注意**  
透過 共用 AWS RAM 需要 中的發起人 AWS RAM 具有許可，才能對正在共用的任何 API 執行 `appsync:PutResourcePolicy`動作。

## 合併
<a name="merges"></a>

### 管理合併
<a name="managing-merges"></a>

合併 APIs旨在支援團隊在統一 AWS AppSync 端點上的協作。團隊可以在後端獨立發展自己的隔離來源 GraphQL APIs，同時 AWS AppSync 服務會管理資源與單一合併 API 端點的整合，以減少協作中的摩擦並縮短開發前置時間。

### 自動合併
<a name="auto-merge"></a>

與 AWS AppSync 合併 APIs 相關聯的來源 API 可以設定為在對來源 API 進行任何變更後自動合併 （自動合併） 到合併 API。這可確保來源 API 的變更一律傳播至背景中的合併 API 端點。只要不會與合併 API 中的現有定義發生合併衝突，來源 API 結構描述中的任何變更都會在合併 API 中更新。如果來源 API 中的更新正在更新解析程式、資料來源或函數，也會更新匯入的資源。發生無法自動解決 （自動解決） 的新衝突時，合併 API 結構描述更新會因為合併操作期間不支援的衝突而被拒絕。錯誤訊息可在 主控台中針對狀態為 的每個來源 API 關聯使用`MERGE_FAILED`。您也可以使用 AWS SDK 或使用 AWS CLI 呼叫指定來源 API 關聯的 `GetSourceApiAssociation`操作來檢查錯誤訊息，如下所示：

```
aws appsync get-source-api-association --merged-api-identifier <Merged API ARN> --association-id <SourceApiAssociation id>
```

這將產生以下格式的結果：

```
{
    "sourceApiAssociation": {
        "associationId": "<association id>",
        "associationArn": "<association arn>",
        "sourceApiId": "<source api id>",
        "sourceApiArn": "<source api arn>",
        "mergedApiArn": "<merged api arn>",
        "mergedApiId": "<merged api id>",
        "sourceApiAssociationConfig": {
            "mergeType": "MANUAL_MERGE"
        },
        "sourceApiAssociationStatus": "MERGE_FAILED",
        "sourceApiAssociationStatusDetail": "Unable to resolve conflict on object with name title: Merging is not supported for fields with different types."
    }
}
```

### 手動合併
<a name="manual-merges"></a>

來源 API 的預設設定是手動合併。若要合併自上次更新合併 API 以來在來源 APIs 中發生的任何變更，來源 API 擁有者可以從 AWS AppSync 主控台或透過 AWS SDK 和 CLI AWS 中可用的`StartSchemaMerge`操作叫用手動合併。

## 合併 APIs的其他支援
<a name="merge-api-additional-support"></a>

### 設定訂閱
<a name="config-subscription"></a>

與以路由器為基礎的 GraphQL 結構描述合成方法不同， AWS AppSync 合併 APIs為 GraphQL 訂閱提供內建支援。您關聯來源 APIs中定義的所有訂閱操作都會自動合併，並在合併 API 中運作，無需修改。若要進一步了解 如何透過無伺服器 WebSockets 連線 AWS AppSync 支援訂閱，請參閱[即時資料](https://docs.aws.amazon.com/appsync/latest/devguide/aws-appsync-real-time-data.html)。

### 設定可觀測性
<a name="config-observability"></a>

AWS AppSync 合併 APIs 透過 [Amazon CloudWatch](https://docs.aws.amazon.com/appsync/latest/devguide/monitoring.html) 提供內建記錄、監控和指標。 AWS AppSync 也提供透過 追蹤的內建支援[AWS X-Ray](https://docs.aws.amazon.com/appsync/latest/devguide/x-ray-tracing.html)。

### 設定自訂網域
<a name="config-custom-domain"></a>

AWS AppSync 合併 APIs提供內建支援，讓您將自訂網域與合併 API 的 [GraphQL 和即時端點](https://docs.aws.amazon.com/appsync/latest/devguide/custom-domain-name.html)搭配使用。

### 設定快取
<a name="config-caching"></a>

AWS AppSync 合併 APIs提供內建支援，可選擇性地快取請求層級和/或解析程式層級的回應，以及回應壓縮。若要進一步了解，請參閱[快取和壓縮](https://docs.aws.amazon.com/appsync/latest/devguide/enabling-caching.html)。

### 設定私有 APIs
<a name="config-private-api"></a>

AWS AppSync 合併 APIs提供私有 APIs 的內建支援，可將對合併 API 的 GraphQL 和即時端點的存取限制為來自[您可以設定的 VPC 端點的](https://docs.aws.amazon.com/appsync/latest/devguide/using-private-apis.html)流量。

### 設定防火牆規則
<a name="config-firewall"></a>

AWS AppSync 合併 APIs提供 的內建支援 AWS WAF，可讓您透過定義 [Web 應用程式防火牆規則](https://docs.aws.amazon.com/appsync/latest/devguide/WAF-Integration.html)來保護 APIs。

### 設定稽核日誌
<a name="config-audit"></a>

AWS AppSync 合併 APIs提供 AWS CloudTrail 的內建支援，可讓您[設定和管理稽核日誌](https://docs.aws.amazon.com/appsync/latest/devguide/cloudtrail-logging.html)。

## 合併 API 限制
<a name="merged-api-limits"></a>

開發合併 APIs 時，請注意下列規則：

1. 合併 API 不能是另一個合併 API 的來源 API。

1. 來源 API 無法與多個合併 API 建立關聯。

1. 合併 API 結構描述文件的預設大小限制為 10 MB。

1. 可與合併 APIs 相關聯的來源 API 預設數量為 10。不過，如果您在合併 APIs中需要超過 10 個來源 API，您可以請求提高限制。

## 合併 API 考量事項
<a name="merged-api-considerations"></a>

設計和實作合併 APIs時，請考慮下列事項：

將多個來源 APIs 合併到單一端點可能會增加 GraphQL 結構描述和查詢的大小和複雜性。隨著合併結構描述的成長，查詢可能需要周遊多個解析程式以滿足單一請求，這可能會為您的整體請求時間增加延遲。例如，從多個來源 APIs 存取欄位的查詢可能需要依序從每個來源 API AWS AppSync 執行解析程式，而每個解析程式都會新增至總回應時間。

我們強烈建議您在開發期間以及在逼真的負載條件下完整測試合併 APIs，以確保它們符合您的業務需求。請特別注意：
+ 合併結構描述的深度和複雜性，特別是跨多個來源 APIs查詢。
+ 必須執行才能滿足常見查詢模式的解析程式數目。
+ 在預期負載下，資料來源和解析程式的效能特性。
+ 跨多個來源 APIs 存取資源時網路延遲的影響。

請考慮實作效能最佳化，例如快取、批次處理資料來源請求，以及設計來源 API 結構描述，以將常見操作所需的解析程式執行次數降至最低。

## 建立合併 APIs
<a name="creating-merged-api"></a>

**在主控台中建立合併 API**

1. 登入 AWS 管理主控台 並開啟 [AWS AppSync 主控台](https://console.aws.amazon.com/appsync/)。

   1. 在**儀表板 **中，選擇**建立 API**。

1. 選擇**合併 API**，然後選擇**下一步**。

1. 在**指定 API 詳細資訊**頁面中，輸入下列資訊：

   1. 在 **API 詳細資訊**下，輸入下列資訊：

      1. 指定合併 API 的 **API 名稱**。此欄位是標記 GraphQL API 的方式，可方便地將其與其他 GraphQL APIs 區分開來。

      1. 指定**聯絡人詳細資訊**。此欄位是選用的，可將名稱或群組連接至 GraphQL API。它不會連結到其他資源或由其他資源產生，運作方式很類似 API 名稱欄位。

   1. 在**服務角色**下，您必須將 IAM 執行角色連接至合併的 API，讓 AWS AppSync 可以在執行時間安全地匯入和使用您的資源。您可以選擇**建立和使用新的服務角色**，這可讓您指定 AWS AppSync 將使用的政策和資源。您也可以匯入現有的 IAM 角色，方法是選擇**使用現有的服務角色**，然後從下拉式清單中選取角色。

   1. 在**私有 API 組態**下，您可以選擇啟用私有 API 功能。請注意，此選項無法在建立合併的 API 之後變更。如需私有 APIs的詳細資訊，請參閱[使用 AWS AppSync 私有 APIs](https://docs.aws.amazon.com/appsync/latest/devguide/using-private-apis.html)。

      完成後，請選擇**下一步**。

1. 接著，您必須新增將用作合併 APIs 基礎的 GraphQL API。在**選取來源 APIs**頁面中，輸入下列資訊：

   1. 在** AWS 帳戶資料表的 APIs 中**，選擇**新增來源 APIs**。在 GraphQL APIs清單中，每個項目都會包含下列資料：

      1. **名稱**：GraphQL API 的 **API 名稱**欄位。

      1. **API ID**：GraphQL API 的唯一 ID 值。

      1. **主要身分驗證模式**：GraphQL API 的預設授權模式。如需 中授權模式的詳細資訊 AWS AppSync，請參閱[授權和身分驗證](https://docs.aws.amazon.com/appsync/latest/devguide/security-authz.html)。

      1. **額外身分驗證模式**：GraphQL API 中設定的次要授權模式。

      1. 透過選取 APIs**名稱**欄位旁的核取方塊，選擇您將在合併 API 中使用的 API。之後，選擇**新增來源 APIs**。選取的 GraphQL APIs會顯示在**您 AWS 帳戶資料表APIs ** 中。

   1. 在**來自其他 AWS 帳戶的 APIs ** 表格中，選擇**新增來源 APIs**。此清單中的 GraphQL APIs 來自透過 AWS Resource Access Manager () 將資源分享給您的其他帳戶AWS RAM。在此資料表中選取 GraphQL APIs的程序與上一節的程序相同。如需透過 共用資源的詳細資訊 AWS RAM，請參閱[什麼是 AWS Resource Access Manager？](https://docs.aws.amazon.com/ram/latest/userguide/what-is.html)。

      完成後，請選擇**下一步**。

   1. 新增您的主要身分驗證模式。如需詳細資訊，請參閱[授權和身分驗證](https://docs.aws.amazon.com/appsync/latest/devguide/security-authz.html)。選擇**下一步**。

   1. 檢閱您的輸入，然後選擇**建立 API**。

# 使用 RDS 自我檢查建置 GraphQL APIs
<a name="rds-introspection"></a>

AWS AppSync的自我檢查公用程式可以從資料庫資料表探索模型，並提議 GraphQL 類型。 AWS AppSync 主控台的建立 API 精靈可以立即從 Aurora MySQL 或 PostgreSQL 資料庫產生 API。它會自動建立類型和 JavaScript 解析程式來讀取和寫入資料。

AWS AppSync 透過 Amazon RDS Data API 提供與 Amazon Aurora 資料庫的直接整合。Amazon RDS Data API 提供連線至 以 AWS AppSync 執行SQL陳述式的安全 HTTP 端點，而不需要持久性資料庫連線。您可以使用此項目為 Aurora 上的 MySQL 和 PostgreSQL 工作負載建立關聯式資料庫 API。

使用 為關聯式資料庫建置 API AWS AppSync 有幾個優點：
+ 您的資料庫不會直接公開給用戶端，將存取點與資料庫本身解耦。
+ 您可以建置專為不同應用程式需求量身打造的專用 APIs，消除前端自訂商業邏輯的需求。這符合 Backend-For-Frontend (BFF) 模式。
+ 您可以使用各種授權模式在 AWS AppSync layer 實作授權和存取控制，以控制存取。連接到資料庫不需要額外的運算資源，例如託管 Web 伺服器或代理連線。
+ 您可以透過訂閱新增即時功能，並透過 AppSync 進行的資料變動會自動推送至連線的用戶端。
+ 用戶端可以使用常見的連接埠，例如 443，透過 HTTPS 連線至 API。

AWS AppSync 從現有的關聯式資料庫輕鬆建置 APIs。其自我檢查公用程式可以從資料庫資料表探索模型，並提議 GraphQL 類型。主控台的*建立 API* AWS AppSync 精靈可以立即從 Aurora MySQL 或 PostgreSQL 資料庫產生 API。它會自動建立類型和 JavaScript 解析程式來讀取和寫入資料。

AWS AppSync 提供整合的 JavaScript 公用程式，可簡化在解析程式中寫入 SQL 陳述式的程序。您可以針對具有動態值的靜態陳述式使用 AWS AppSync的`sql`標籤範本，或以程式設計方式建置陳述式的`rds`模組公用程式。如需詳細資訊，請參閱 [RDS 資料來源的解析程式函數參考](https://docs.aws.amazon.com//appsync/latest/devguide/resolver-reference-rds-js.html)和[內建模組](https://docs.aws.amazon.com//appsync/latest/devguide/built-in-modules-js.html#built-in-rds-modules)。

## 使用自我檢查功能 （主控台）
<a name="using-introspection-console"></a>

如需詳細的教學課程和入門指南，請參閱[教學課程：Aurora PostgreSQL Serverless with Data API](https://docs.aws.amazon.com//appsync/latest/devguide/aurora-serverless-tutorial-js.html)。

 AWS AppSync 主控台可讓您從使用資料 API 設定的現有 Aurora 資料庫，在幾分鐘內建立 AWS AppSync GraphQL API。這會根據您的資料庫組態快速產生操作結構描述。您可以依原狀使用 API，或在 API 上建置以新增功能。

1. 登入 AWS 管理主控台 並開啟 [AppSync 主控台](https://console.aws.amazon.com/appsync/)。

   1. 在**儀表板**上，選擇 **Create API (建立 API)**。

1. 在 **API 選項**下，選擇 **GraphQL APIs**、**從 Amazon Aurora 叢集開始**，然後選擇**下一步**。

   1. 輸入 **API 名稱**。這將用作 主控台中 API 的識別符。

   1. 如需**聯絡詳細資訊**，您可以輸入聯絡點來識別 API 的管理員。此為選用欄位。

   1. 在**私有 API 組態**下，您可以啟用私有 API 功能。私有 API 只能從設定的 VPC 端點 (VPCE) 存取。如需詳細資訊，請參閱[私有 APIs](https://docs.aws.amazon.com//appsync/latest/devguide/using-private-apis.html)。

      不建議在此範例中啟用此功能。檢閱您的輸入後，請選擇**下一步**。

1. 在**資料庫**頁面中，選擇**選取資料庫**。

   1. 您需要從叢集中選擇資料庫。第一步是選擇叢集所在的**區域**。

   1. 從下拉式清單中選擇 **Aurora 叢集**。請注意，您必須先建立並[啟用](https://docs.aws.amazon.com//AmazonRDS/latest/AuroraUserGuide/data-api.html#data-api.enabling)對應的資料 API，才能使用 資源。

   1. 接著，您必須將資料庫的登入資料新增至服務。這主要是使用 完成 AWS Secrets Manager。選擇您秘密所在的**區域**。如需如何擷取秘密資訊的詳細資訊，請參閱[尋找秘密](https://docs.aws.amazon.com//secretsmanager/latest/userguide/manage_search-secret.html)或[擷取秘密](https://docs.aws.amazon.com//secretsmanager/latest/userguide/retrieving-secrets.html)。

   1. 從下拉式清單中新增您的秘密。請注意，使用者必須具有資料庫的[讀取許可](https://docs.aws.amazon.com//AmazonRDS/latest/UserGuide/security_iam_id-based-policy-examples.html#security_iam_id-based-policy-examples-console)。

1. 選擇**匯入**。

   AWS AppSync 將開始自我檢查資料庫、探索資料表、資料欄、主索引鍵和索引。它會檢查是否可以在 GraphQL API 中支援探索到的資料表。請注意，若要支援建立新的資料列，資料表需要主索引鍵，可以使用多個 column. AWS AppSync maps 資料表資料欄來輸入欄位，如下所示：    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/rds-introspection.html)

1. 資料表探索完成後，**資料庫**區段將填入您的資訊。在新的**資料庫資料表**區段中，資料表中的資料可能已填入並轉換為結構描述的類型。如果您沒有看到一些必要資料，您可以選擇**新增資料表**，按一下出現的模態中這些類型的核取方塊，然後選擇**新增**來檢查它。

   若要從**資料庫資料表**區段中移除類型，請按一下您要移除的類型旁的核取方塊，然後選擇**移除**。如果您想要稍後再次新增，移除的類型將放置在**新增資料表**模態中。

   請注意， AWS AppSync 使用資料表名稱做為類型名稱，但您可以重新命名它們，例如，將*電影*等複數資料表名稱變更為類型名稱*電影*。若要重新命名**資料庫資料表**區段中的類型，請按一下您要重新命名之類型的核取方塊，然後按一下**類型名稱**欄中的*鉛筆*圖示。

   若要根據您的選擇預覽結構描述的內容，請選擇**預覽結構描述**。請注意，此結構描述不能為空白，因此您必須至少有一個資料表轉換為 類型。此外，此結構描述的大小不能超過 1 MB。

   1. 在**服務角色**下，選擇是否要特別為此匯入建立新的服務角色，或使用現有的角色。

1. 選擇**下一步**。

1. 接著，選擇是否建立唯讀 API （僅限查詢） 或用於讀取和寫入資料的 API （含查詢和變動）。後者也支援由變動觸發的即時訂閱。

1. 選擇**下一步**。

1. 檢閱您的選擇，然後選擇**建立 API**。 AWS AppSync 會建立 API，並將解析程式連接至查詢和變動。產生的 API 可完全運作，並可視需要擴充。

## 使用自我檢查功能 (API)
<a name="using-introspection-api"></a>

您可以使用`StartDataSourceIntrospection`自我檢查 API，以程式設計方式探索資料庫中的模型。如需 命令的詳細資訊，請參閱使用 [https://docs.aws.amazon.com//appsync/latest/APIReference/API_StartDataSourceIntrospection.html](https://docs.aws.amazon.com//appsync/latest/APIReference/API_StartDataSourceIntrospection.html) API。

若要使用 `StartDataSourceIntrospection`，請提供您的 Aurora 叢集 Amazon Resource Name (ARN)、資料庫名稱和 AWS Secrets Manager 秘密 ARN。命令會啟動自我檢查程序。您可以使用 `GetDataSourceIntrospection`命令擷取結果。您可以指定命令是否應傳回所探索模型的儲存定義語言 (SDL) 字串。這對於直接從探索到的模型產生 SDL 結構描述定義非常有用。

 例如，如果您有下列簡單`Todos`資料表的資料定義語言 (DDL) 陳述式：

```
create table if not exists public.todos  
(  
id serial constraint todos_pk primary key,  
description text,  
due timestamp,  
"createdAt" timestamp default now()  
);
```

您可以使用下列項目開始自我檢查。

```
aws appsync start-data-source-introspection \ 
  --rds-data-api-config resourceArn=<cluster-arn>,secretArn=<secret-arn>,databaseName=database
```

接著，使用 `GetDataSourceIntrospection`命令來擷取結果。

```
aws appsync get-data-source-introspection \
  --introspection-id a1234567-8910-abcd-efgh-identifier \
  --include-models-sdl
```

這會傳回下列結果。

```
{
    "introspectionId": "a1234567-8910-abcd-efgh-identifier",
    "introspectionStatus": "SUCCESS",
    "introspectionStatusDetail": null,
    "introspectionResult": {
        "models": [
            {
                "name": "todos",
                "fields": [
                    {
                        "name": "description",
                        "type": {
                            "kind": "Scalar",
                            "name": "String",
                            "type": null,
                            "values": null
                        },
                        "length": 0
                    },
                    {
                        "name": "due",
                        "type": {
                            "kind": "Scalar",
                            "name": "AWSDateTime",
                            "type": null,
                            "values": null
                        },
                        "length": 0
                    },
                    {
                        "name": "id",
                        "type": {
                            "kind": "NonNull",
                            "name": null,
                            "type": {
                                "kind": "Scalar",
                                "name": "Int",
                                "type": null,
                                "values": null
                            },
                            "values": null
                        },
                        "length": 0
                    },
                    {
                        "name": "createdAt",
                        "type": {
                            "kind": "Scalar",
                            "name": "AWSDateTime",
                            "type": null,
                            "values": null
                        },
                        "length": 0
                    }
                ],
                "primaryKey": {
                    "name": "PRIMARY_KEY",
                    "fields": [
                        "id"
                    ]
                },
                "indexes": [],
                "sdl": "type todos\n{\ndescription: String\n\ndue: AWSDateTime\n\nid: Int!\n\ncreatedAt: AW
SDateTime\n}\n"
            }
        ],
        "nextToken": null
    }
}
```