

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

# AWS AppSync JavaScript 解析程式概觀
<a name="resolver-reference-overview-js"></a>

AWS AppSync 可讓您透過對資料來源執行操作來回應 GraphQL 請求。對於您想要執行查詢、變動或訂閱的每個 GraphQL 欄位，必須連接解析程式。

解析程式是 GraphQL 和資料來源之間的連接器。他們 tell AWS AppSync 如何將傳入的 GraphQL 請求轉譯為後端資料來源的指示，以及如何將來自該資料來源的回應轉譯回 GraphQL 回應。透過 AWS AppSync，您可以使用 JavaScript 撰寫解析程式，並在 AWS AppSync (`APPSYNC_JS`) 環境中執行。

AWS AppSync 可讓您撰寫由管道中多個 AWS AppSync 函數組成的單位解析程式或管道解析程式。

## 支援的執行時間功能
<a name="runtime-support-js"></a>

 AWS AppSync JavaScript 執行時間提供 JavaScript 程式庫、公用程式和功能的子集。如需`APPSYNC_JS`執行時間支援的完整功能清單，請參閱[解析程式和函數的 JavaScript 執行時間功能](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference-js.html)。

## 單位解析程式
<a name="unit-resolver-js"></a>

單位解析程式由程式碼組成，可定義針對資料來源執行的請求和回應處理常式。請求處理常式會將內容物件做為引數，並傳回用來呼叫資料來源的請求承載。回應處理常式會從資料來源接收承載，其中包含執行請求的結果。回應處理常式會將承載轉換為 GraphQL 回應，以解析 GraphQL 欄位。在下列範例中，解析程式會從 DynamoDB 資料來源擷取項目：

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

export function request(ctx) {
  return ddb.get({ key: { id: ctx.args.id } });
}

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

## JavaScript 管道解析程式的剖析
<a name="anatomy-of-a-pipeline-resolver-js"></a>

管道解析程式由程式碼組成，可定義請求和回應處理常式，以及函數清單。每個函數都有一個針對資料來源執行的**請求**和**回應**處理常式。由於管道解析程式委派會執行到函數清單，因此不會連結到任何資料來源。單位解析程式和函數是對資料來源執行操作的基本元素。

### 管道解析程式請求處理常式
<a name="request-handler-js"></a>

管道解析程式的請求處理常式 （步驟前） 可讓您在執行定義的函數之前執行一些準備邏輯。

### 函數清單
<a name="functions-list-js"></a>

管道解析程式將會依序執行的函數清單。管道解析程式請求處理常式評估結果會以 的形式提供給第一個函數`ctx.prev.result`。每個函數評估結果都以 的形式提供給下一個函數`ctx.prev.result`。

### 管道解析程式回應處理常式
<a name="response-handler-js"></a>

管道解析程式的回應處理常式可讓您執行從最後一個函數輸出到預期 GraphQL 欄位類型的一些最終邏輯。函數清單中最後一個函數的輸出可在管道解析程式回應處理常式中作為 `ctx.prev.result`或 使用`ctx.result`。

### 執行流程
<a name="execution-flow-js"></a>

假設管道解析程式包含兩個函數，以下清單代表呼叫解析程式時的執行流程：

1.  管道解析程式請求處理常式

1.  函數 1：函數請求處理常式 

1.  第 1 個函數：資料來源呼叫 

1.  函數 1：函數回應處理常式 

1.  函數 2：函數請求處理常式 

1.  第 2 個函數：資料來源呼叫 

1.  函數 2：函數回應處理常式 

1.  管道解析程式回應處理常式 

![\[GraphQL request flow diagram showing interactions between request, data sources, and response components.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/appsync-js-resolver-logic.png)


### 實用的`APPSYNC_JS`執行期內建公用程式
<a name="useful-utilities-js"></a>

下列公用程式可在您使用管道解析程式時提供協助。

#### ctx.stash
<a name="ctx-stash-js"></a>

停滯是在每個解析程式和函數請求和回應處理常式中可用的物件。相同的 stash 執行個體透過單一解析程式執行運作。這表示您可以使用 stash 跨請求和回應處理常式，以及管道解析程式中的函數傳遞任意資料。您可以像一般 JavaScript 物件一樣測試堆疊。

#### ctx.prev.result
<a name="ctx-prev-result-js"></a>

`ctx.prev.result` 會顯示管道先前執行操作的結果。如果先前的操作是管道解析程式請求處理常式，則 `ctx.prev.result` 可供鏈結中的第一個函數使用。如果先前操作是第一個函數，則 `ctx.prev.result` 會顯示第一個函數的輸出，並將資料提供給管道中的第二個函數。如果先前的操作是最後一個函數，則 `ctx.prev.result` 代表最後一個函數的輸出，並可供管道解析程式回應處理常式使用。

#### util.error
<a name="util-error-js"></a>

`util.error` 公用程式非常適合用來擲出欄位錯誤。在函數請求或回應處理常式`util.error`內使用 會立即擲回欄位錯誤，以防止後續函數執行。如需詳細資訊和其他`util.error`簽章，請造訪[解析程式和函數的 JavaScript 執行期功能](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference-js.html)。

#### util.appendError
<a name="util-appenderror-js"></a>

`util.appendError` 類似於 `util.error()`，主要區別在於它不會中斷處理常式的評估。相反地，它表示 欄位發生錯誤，但允許評估處理常式並因此傳回資料。在函數中使用 `util.appendError` 並不會中斷管道的執行流程。如需詳細資訊和其他`util.error`簽章，請造訪[解析程式和函數的 JavaScript 執行期功能](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference-js.html)。

#### runtime.earlyReturn
<a name="runtime-earlyreturn-js"></a>

`runtime.earlyReturn` 函數可讓您從任何請求函數提早傳回 。在解析程式請求處理常式`runtime.earlyReturn`內部使用 會從解析程式傳回 。從函數 AWS AppSync 請求處理常式呼叫它會從函數傳回，並繼續執行到管道中的下一個函數或解析程式回應處理常式。

### 撰寫管道解析程式
<a name="writing-resolvers"></a>

管道解析程式也有一個請求和一個回應處理常式，圍繞管道中函數的執行：其請求處理常式在第一個函數的請求之前執行，而其回應處理常式在最後一個函數的回應之後執行。解析程式請求處理常式可以設定要供管道中的函數使用的資料。解析程式回應處理常式負責傳回映射至 GraphQL 欄位輸出類型的資料。在下列範例中，解析程式請求處理常式會定義 `allowedGroups`；傳回的資料應屬於其中一個群組。此值可供解析程式的 函數用來請求資料。解析程式的回應處理常式會執行最終檢查並篩選結果，以確保只會傳回屬於允許群組的項目。

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

/**
 * Called before the request function of the first AppSync function in the pipeline.
 *  @param ctx the context object holds contextual information about the function invocation.
 */
export function request(ctx) {
  ctx.stash.allowedGroups = ['admin'];
  ctx.stash.startedAt = util.time.nowISO8601();
  return {};
}
/**
 * Called after the response function of the last AppSync function in the pipeline.
 * @param ctx the context object holds contextual information about the function invocation.
 */
export function response(ctx) {
  const result = [];
  for (const item of ctx.prev.result) {
    if (ctx.stash.allowedGroups.indexOf(item.group) > -1) result.push(item);
  }
  return result;
}
```

#### 撰寫 AWS AppSync 函數
<a name="writing-functions"></a>

AWS AppSync 函數可讓您撰寫常見邏輯，以便在結構描述中的多個解析程式之間重複使用。例如，您可以有一個稱為 `QUERY_ITEMS` 的 AWS AppSync 函數，負責從 Amazon DynamoDB 資料來源查詢項目。對於您要查詢項目的解析程式，只需將 函數新增至解析程式的管道，並提供要使用的查詢索引。邏輯不需要重新實作。

## 補充主題
<a name="supplemental-topics"></a>

**主題**
+ [使用 Amazon DynamoDB 的範例管道解析程式](https://docs.aws.amazon.com/appsync/latest/devguide/writing-code.html)
+ [設定`APPSYNC_JS`執行時間的公用程式](https://docs.aws.amazon.com/appsync/latest/devguide/utility-resolvers.html)
+ [`APPSYNC_JS`執行時間的綁定、TypeScript 和來源映射](https://docs.aws.amazon.com/appsync/latest/devguide/additional-utilities.html)
+ [測試您的解析程式和函數處理常式](https://docs.aws.amazon.com/appsync/latest/devguide/test-resolvers.html)
+ [從 VTL 遷移到 JavaScript](https://docs.aws.amazon.com/appsync/latest/devguide/migrating-resolvers.html)
+ [在直接資料來源存取和透過 Lambda 資料來源代理之間進行選擇](https://docs.aws.amazon.com/appsync/latest/devguide/choosing-data-source.html)

# 使用 Amazon DynamoDB 的範例管道解析程式
<a name="writing-code"></a>

假設您想要在名為 的欄位上連接管道解析程式`getPost(id:ID!)`，該欄位會從具有下列 GraphQL 查詢的 Amazon DynamoDB 資料來源傳回`Post`類型：

```
getPost(id:1){
    id
    title
    content
}
```

首先，`Query.getPost`使用下面的程式碼將簡單的解析程式連接到 。這是簡單解析程式程式碼的範例。請求處理常式中未定義邏輯，回應處理常式只會傳回最後一個函數的結果。

```
/**
 * Invoked **before** the request handler of the first AppSync function in the pipeline.
 * The resolver `request` handler allows to perform some preparation logic
 * before executing the defined functions in your pipeline.
 * @param ctx the context object holds contextual information about the function invocation.
 */
export function request(ctx) {
  return {}
}

/**
 * Invoked **after** the response handler of the last AppSync function in the pipeline.
 * The resolver `response` handler allows to perform some final evaluation logic
 * from the output of the last function to the expected GraphQL field type.
 * @param ctx the context object holds contextual information about the function invocation.
 */
export function response(ctx) {
  return ctx.prev.result
}
```

接著，定義從資料來源擷取後置項目`GET_ITEM`的函數：

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

/**
 * Request a single item from the attached DynamoDB table datasource
 * @param ctx the context object holds contextual information about the function invocation.
 */
export function request(ctx) {
	const { id } = ctx.args
	return ddb.get({ key: { id } })
}

/**
 * Returns the result
 * @param ctx the context object holds contextual information about the function invocation.
 */
export function response(ctx) {
	const { error, result } = ctx
	if (error) {
		return util.appendError(error.message, error.type, result)
	}
	return ctx.result
}
```

如果在請求期間發生錯誤，函數的回應處理常式會附加錯誤，並在 GraphQL 回應中傳回呼叫用戶端。將 `GET_ITEM`函數新增至解析程式函數清單。當您執行查詢時，`GET_ITEM`函數的請求處理常式會使用 AWS AppSync DynamoDB 模組提供的 utils，以使用 `id`做為金鑰來建立`DynamoDBGetItem`請求。 `ddb.get({ key: { id } })`會產生適當的`GetItem`操作：

```
{
    "operation" : "GetItem",
    "key" : {
        "id" : { "S" : "1" }
    }
}
```

AWS AppSync 使用 請求從 Amazon DynamoDB 擷取資料。一旦傳回資料，就會由`GET_ITEM`函數的回應處理常式處理，它會檢查錯誤，然後傳回結果。

```
{
  "result" : {
    "id": 1,
    "title": "hello world",
    "content": "<long story>"
  }
}
```

最後，解析程式的回應處理常式會直接傳回結果。

## 使用錯誤
<a name="working-with-errors"></a>

如果在請求期間函數中發生錯誤，則會在 中的函數回應處理常式中提供該錯誤`ctx.error`。您可以使用 `util.appendError`公用程式將錯誤附加至 GraphQL 回應。您可以使用 stash，將錯誤提供給管道中的其他 函數。請參閱以下範例：

```
/**
 * Returns the result
 * @param ctx the context object holds contextual information about the function invocation.
 */
export function response(ctx) {
  const { error, result } = ctx;
  if (error) {
    if (!ctx.stash.errors) ctx.stash.errors = []
    ctx.stash.errors.push(ctx.error)
    return util.appendError(error.message, error.type, result);
  }
  return ctx.result;
}
```

# 設定`APPSYNC_JS`執行時間的公用程式
<a name="utility-resolvers"></a>

AWS AppSync 提供兩個程式庫，協助開發具有`APPSYNC_JS`執行時間的解析程式：
+ `@aws-appsync/eslint-plugin` - 在開發期間快速攔截和修正問題。
+ `@aws-appsync/utils` - 在程式碼編輯器中提供類型驗證和自動完成。

## 設定 eslint 外掛程式
<a name="utility-resolvers-configuring-eslint-plugin"></a>

[ESLint](https://eslint.org/) 是一種工具，可靜態分析程式碼以快速找出問題。您可以執行 ESLint 做為持續整合管道的一部分。 `@aws-appsync/eslint-plugin` 是一種 ESLint 外掛程式，在利用`APPSYNC_JS`執行時間時，可在程式碼中擷取無效的語法。外掛程式可讓您在開發期間快速取得程式碼的意見回饋，而不必將變更推送至雲端。

`@aws-appsync/eslint-plugin` 提供兩個規則集，您可以在開發期間使用。

**「plugin：@aws-appsync/base」**會設定一組基本規則，供您在專案中運用：


| 規則 | Description | 
| --- | --- | 
| 無非同步 | 不支援非同步程序和承諾。 | 
| 無等待 | 不支援非同步程序和承諾。 | 
| 無類別 | 不支援類別。 | 
| 無 | for 不支援 (for-of受支援的 for-in和 除外） | 
| 不繼續 | 不支援 continue。 | 
| 無生成器 | 不支援產生器。 | 
| 無產出 | 不支援 yield。 | 
| 無標籤 | 不支援標籤。 | 
| 否-此 | this 不支援 關鍵字。 | 
| 無嘗試 | 不支援 Try/catch 結構。 | 
| 無同時 | 雖然不支援迴圈。 | 
| no-disallowed-unary-operators | \$1\$1不允許 、 --和 \$1 unary 運算子。 | 
| no-disallowed-binary-operators | 不允許 instanceof運算子。 | 
| 無承諾 | 不支援非同步程序和承諾。 | 

**「plugin：@aws-appsync/recommended」**提供一些額外的規則，但也需要您將 TypeScript 組態新增至專案。


| 規則 | Description | 
| --- | --- | 
| 無遞迴 | 不允許遞迴函數呼叫。 | 
| no-disallowed-methods | 不允許某些方法。如需完整的支援內建函數，請參閱 [參考](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference-js.html)。 | 
| no-function-passing | 不允許將函數做為函數引數傳遞至函數。 | 
| no-function-reassign | 無法重新指派函數。 | 
| no-function-return | 函數不能是函數的傳回值。 | 

若要將外掛程式新增至您的專案，請遵循 [ ESLint 入門](https://eslint.org/docs/latest/user-guide/getting-started#installation-and-usage)中的安裝和使用步驟。然後，使用您的專案套件管理員在您的專案中安裝[外掛程式](https://www.npmjs.com/package/@aws-appsync/eslint-plugin) （例如 npm、 yarn 或 pnpm)：

```
$ npm install @aws-appsync/eslint-plugin
```

在您的 `.eslintrc.{js,yml,json}`檔案中，將**「plugin：@aws-appsync/base」**或**「plugin：@aws-appsync/recommended」**新增至 `extends` 屬性。以下程式碼片段是 JavaScript 的基本範例`.eslintrc`組態：

```
{
  "extends": ["plugin:@aws-appsync/base"]
}
```

若要使用**「plugin：@aws-appsync/recommended」**規則集，請安裝必要的相依性：

```
$ npm install -D @typescript-eslint/parser
```

然後，建立 `.eslintrc.js` 檔案：

```
{
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": 2018,
    "project": "./tsconfig.json"
  },
  "extends": ["plugin:@aws-appsync/recommended"]
}
```

# `APPSYNC_JS` 執行時間的綁定、TypeScript 和來源映射
<a name="additional-utilities"></a>

TypeScript 透過提供類型安全和早期錯誤偵測來增強 AWS AppSync 開發。您可以在本機撰寫 TypeScript 程式碼並將其轉換為 JavaScript，然後再與`APPSYNC_JS`執行時間搭配使用。程序從安裝 TypeScript 和為`APPSYNC_JS`環境設定 tsconfig.json 開始。然後，您可以使用 esbuild 等綁定工具來編譯和綁定程式碼。Amplify CLI 會從 GraphQL 結構描述產生類型，讓您可以在解析程式程式碼中使用這些類型。

只要符合`APPSYNC_JS`要求，您就可以在解析程式和函數程式碼中利用自訂和外部程式庫。綁定工具將程式碼合併為單一檔案以供使用 AWS AppSync。可以包含來源映射以協助偵錯。

## 利用程式庫並綁定程式碼
<a name="using-external-libraries"></a>

在解析程式和函數程式碼中，只要符合`APPSYNC_JS`要求，您就可以利用自訂程式庫和外部程式庫。這可讓您在應用程式中重複使用現有的程式碼。若要使用由多個檔案定義的程式庫，您必須使用綁定工具，例如 [esbuild](https://esbuild.github.io/)，將程式碼合併到單一檔案中，然後儲存到 AWS AppSync 解析程式或函數。

綁定程式碼時，請記住下列事項：
+ `APPSYNC_JS` 僅支援 ECMAScript 模組 (ESM)。
+ `@aws-appsync/*` 模組已整合至 `APPSYNC_JS` ，且不應與您的程式碼綁定。
+ `APPSYNC_JS` 執行時間環境類似於 NodeJS，因為該程式碼不會在瀏覽器環境中執行。
+ 您可以包含選用的來源映射。不過，請勿包含來源內容。

  若要進一步了解來源映射，請參閱[使用來源映射](#source-maps)。

例如，若要綁定位於 的解析程式程式碼`src/appsync/getPost.resolver.js`，您可以使用下列 esbuild CLI 命令：

```
$ esbuild --bundle \
--sourcemap=inline \
--sources-content=false \
--target=esnext \
--platform=node \
--format=esm \
--external:@aws-appsync/utils \
--outdir=out/appsync \
 src/appsync/getPost.resolver.js
```

## 建置程式碼並使用 TypeScript
<a name="working-with-typescript"></a>

[TypeScript](https://www.typescriptlang.org/) 是由 Microsoft 開發的一種程式設計語言，可提供 JavaScript 的所有功能以及 TypeScript 類型系統。您可以使用 TypeScript 撰寫安全類型的程式碼，並在建置時擷取錯誤和錯誤，再將程式碼儲存至 AWS AppSync。`@aws-appsync/utils` 套件已完全輸入。

`APPSYNC_JS` 執行時間不支援 TypeScript。您必須先將 TypeScript 程式碼轉換為`APPSYNC_JS`執行時間支援的 JavaScript 程式碼，才能將程式碼儲存到其中 AWS AppSync。您可以使用 TypeScript 在本機整合開發環境 (IDE) 中撰寫程式碼，但請注意，您無法在 AWS AppSync 主控台中建立 TypeScript 程式碼。

若要開始使用，請確定專案中已安裝 [TypeScript](https://www.typescriptlang.org/download)。然後，設定 TypeScript 轉編譯設定，以使用 [TSConfig](https://www.typescriptlang.org/tsconfig) 搭配`APPSYNC_JS`執行時間。以下是您可以使用的基本`tsconfig.json`檔案範例：

```
// tsconfig.json
{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
   "noEmit": true,
   "moduleResolution": "node",
  }
}
```

然後，您可以使用 esbuild 等綁定工具來編譯和綁定程式碼。例如，假設專案的 AWS AppSync 程式碼位於 `src/appsync`，您可以使用下列命令來編譯和綁定程式碼：

```
$ esbuild --bundle \
--sourcemap=inline \
--sources-content=false \
--target=esnext \
--platform=node \
--format=esm \
--external:@aws-appsync/utils \
--outdir=out/appsync \
 src/appsync/**/*.ts
```

### 使用 Amplify codegen
<a name="working-with-amplify-codegen"></a>

您可以使用 [Amplify CLI](https://docs.amplify.aws/cli/) 來產生結構描述的類型。從`schema.graphql`檔案所在的目錄中，執行下列命令並檢閱提示以設定您的 Codegen：

```
$  npx @aws-amplify/cli codegen add
```

若要在某些情況下 （例如，結構描述更新時） 重新產生您的程式碼，請執行下列命令：

```
$ npx @aws-amplify/cli codegen
```

然後，您可以在解析程式程式碼中使用產生的類型。例如，指定下列結構描述：

```
type Todo {
  id: ID!
  title: String!
  description: String
}

type Mutation {
  createTodo(title: String!, description: String): Todo
}

type Query {
  listTodos: Todo
}
```

您可以在下列範例 AWS AppSync 函數中使用產生的類型：

```
import { Context, util } from '@aws-appsync/utils'
import * as ddb from '@aws-appsync/utils/dynamodb'
import { CreateTodoMutationVariables, Todo } from './API' // codegen

export function request(ctx: Context<CreateTodoMutationVariables>) {
	ctx.args.description = ctx.args.description ?? 'created on ' + util.time.nowISO8601()
	return ddb.put<Todo>({ key: { id: util.autoId() }, item: ctx.args })
}

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

### 在 TypeScript 中使用通用
<a name="working-with-typescript-generics"></a>

您可以搭配多種提供的類型使用學名藥。例如，以下程式碼片段是一種`Todo`類型：

```
export type Todo = {
  __typename: "Todo",
  id: string,
  title: string,
  description?: string | null,
};
```

您可以為使用 的訂閱撰寫解析程式`Todo`。在您的 IDE 中，輸入定義和自動完成提示將引導您正確使用`toSubscriptionFilter`轉換公用程式：

```
import { util, Context, extensions } from '@aws-appsync/utils'
import { Todo } from './API'

export function request(ctx: Context) {
  return {}
}

export function response(ctx: Context) {
  const filter = util.transform.toSubscriptionFilter<Todo>({
    title: { beginsWith: 'hello' },
    description: { contains: 'created' },
  })
  extensions.setSubscriptionFilter(filter)
  return null
}
```

## 內嵌您的套件
<a name="using-lint-with-bundles"></a>

您可以透過匯入 `esbuild-plugin-eslint` 外掛程式自動繫結套件。然後，您可以提供啟用隱含功能`plugins`的值來啟用它。以下是在名為 的檔案中使用 esbuild JavaScript API 的程式碼片段`build.mjs`：

```
/* eslint-disable */
import { build } from 'esbuild'
import eslint from 'esbuild-plugin-eslint'
import glob from 'glob'
const files = await glob('src/**/*.ts')

await build({
  format: 'esm',
  target: 'esnext',
  platform: 'node',
  external: ['@aws-appsync/utils'],
  outdir: 'dist/',
  entryPoints: files,
  bundle: true,
  plugins: [eslint({ useEslintrc: true })],
})
```

## 使用來源映射
<a name="source-maps"></a>

您可以使用 JavaScript 程式碼提供內嵌來源映射 (`sourcemap`)。當您綁定 JavaScript 或 TypeScript 程式碼，並想要在日誌和執行時間 JavaScript 錯誤訊息中查看對輸入來源檔案的參考時，來源映射非常有用。

您的 `sourcemap` 必須出現在程式碼的結尾。它由遵循下列格式的單一註解行定義：

```
//# sourceMappingURL=data:application/json;base64,<base64 encoded string>
```

範例如下：

```
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsibGliLmpzIiwgImNvZGUuanMiXSwKICAibWFwcGluZ3MiOiAiO0FBQU8sU0FBUyxRQUFRO0FBQ3RCLFNBQU87QUFDVDs7O0FDRE8sU0FBUyxRQUFRLEtBQUs7QUFDM0IsU0FBTyxNQUFNO0FBQ2Y7IiwKICAibmFtZXMiOiBbXQp9Cg==
```

您可以使用 esbuild 建立來源映射。以下範例說明如何在建置和綁定程式碼時，使用 esbuild JavaScript API 來包含內嵌來源映射：

```
/* eslint-disable */
import { build } from 'esbuild'
import eslint from 'esbuild-plugin-eslint'
import glob from 'glob'
const files = await glob('src/**/*.ts')

await build({
  sourcemap: 'inline',
  sourcesContent: false,
  
  format: 'esm',
  target: 'esnext',
  platform: 'node',
  external: ['@aws-appsync/utils'],
  outdir: 'dist/',
  entryPoints: files,
  bundle: true,
  plugins: [eslint({ useEslintrc: true })],
})
```

特別是， `sourcemap`和 `sourcesContent`選項指定應該在每個組建結束時逐行新增來源映射，但不應包含來源內容。作為慣例，我們建議您不要在 中包含來源內容`sourcemap`。您可以將 `sources-content`設定為 ，在 esbuild 中停用此功能`false`。

若要說明來源映射的運作方式，請檢閱下列解析程式程式碼參考協助程式程式庫中協助程式函數的範例。此程式碼包含解析程式程式碼和協助程式程式程式庫中的日誌陳述式：

**./src/default.resolver.ts** （您的解析程式）

```
import { Context } from '@aws-appsync/utils'
import { hello, logit } from './helper'

export function request(ctx: Context) {
  console.log('start >')
  logit('hello world', 42, true)
  console.log('< end')
  return 'test'
}

export function response(ctx: Context): boolean {
  hello()
  return ctx.prev.result
}
```

**.src/helper.ts** （協助程式檔案）

```
export const logit = (...rest: any[]) => {
  // a special logger
  console.log('[logger]', ...rest.map((r) => `<${r}>`))
}

export const hello = () => {
  // This just returns a simple sentence, but it could do more.
  console.log('i just say hello..')
}
```

當您建置和綁定解析程式檔案時，您的解析程式程式碼將包含內嵌來源映射。當您的解析程式執行時，以下項目會出現在 CloudWatch 日誌中：

![\[CloudWatch log entries showing resolver code execution with inline source map information.\]](http://docs.aws.amazon.com/zh_tw/appsync/latest/devguide/images/cloudwatch-sourcemap.jpeg)


查看 CloudWatch 日誌中的項目，您會注意到這兩個檔案的功能已綁定在一起並同時執行。每個檔案的原始檔案名稱也會清楚地反映在日誌中。

# 在 中測試您的解析程式和函數處理常式 AWS AppSync
<a name="test-resolvers"></a>

您可以使用 `EvaluateCode` API 命令，在將程式碼儲存到解析程式或函數之前，使用模擬資料遠端測試解析程式和函數處理常式。若要開始使用 命令，請確定您已將 `appsync:evaluatecode`許可新增至政策。例如：

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

****  

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

------

您可以使用 [AWS CLI ](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/appsync/index.html)或 [AWS SDKs](https://aws.amazon.com/tools/) 來利用 命令。例如，若要使用 CLI 測試程式碼，只需指向 檔案、提供內容，並指定您要評估的處理常式：

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

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

```
{
    "evaluationResult": "{\"operation\":\"PutItem\",\"key\":{\"id\":{\"S\":\"record-id\"}},\"attributeValues\":{\"owner\":{\"S\":\"John doe\"},\"expectedVersion\":{\"N\":2},\"authorId\":{\"S\":\"Sammy Davis\"}}}",
    "logs": [
        "INFO - code.js:5:3: \"current id\" \"record-id\"",
        "INFO - code.js:9:3: \"request evaluated\""
    ]
}
```

評估結果可以剖析為 JSON，其提供：

```
{
  "operation": "PutItem",
  "key": {
    "id": {
      "S": "record-id"
    }
  },
  "attributeValues": {
    "owner": {
      "S": "John doe"
    },
    "expectedVersion": {
      "N": 2
    },
    "authorId": {
      "S": "Sammy Davis"
    }
  }
}
```

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

# 在 中從 VTL 遷移至 JavaScript AWS AppSync
<a name="migrating-resolvers"></a>

AWS AppSync 可讓您使用 VTL 或 JavaScript 為您的解析程式和函數撰寫商業邏輯。使用這兩種語言時，您會撰寫邏輯，指示 AWS AppSync 服務如何與資料來源互動。使用 VTL，您撰寫的映射範本必須評估為有效的 JSON 編碼字串。使用 JavaScript，您可以撰寫傳回物件的請求和回應處理常式。您不會傳回 JSON 編碼字串。

例如，採用下列 VTL 映射範本來取得 Amazon DynamoDB 項目：

```
{
    "operation": "GetItem",
    "key": {
        "id": $util.dynamodb.toDynamoDBJson($ctx.args.id),
    }
}
```

公用程式`$util.dynamodb.toDynamoDBJson`會傳回 JSON 編碼字串。如果 `$ctx.args.id` 設定為 `<id>`，範本會評估為有效的 JSON 編碼字串：

```
{
    "operation": "GetItem",
    "key": {
        "id": {"S": "<id>"},
    }
}
```

使用 JavaScript 時，您不需要在程式碼中列印原始 JSON 編碼字串，而且`toDynamoDBJson`不需要像 一樣使用公用程式。上述映射範本的同等範例為：

```
import { util } from '@aws-appsync/utils';
export function request(ctx) {
  return {
    operation: 'GetItem',
    key: {id: util.dynamodb.toDynamoDB(ctx.args.id)}
  };
}
```

另一種方法是使用 `util.dynamodb.toMapValues`，這是處理值物件的建議方法：

```
import { util } from '@aws-appsync/utils';
export function request(ctx) {
  return {
    operation: 'GetItem',
    key: util.dynamodb.toMapValues({ id: ctx.args.id }),
  };
}
```

這會評估為：

```
{
  "operation": "GetItem",
  "key": {
    "id": {
      "S": "<id>"
    }
  }
}
```

**注意**  
我們建議您搭配 DynamoDB 資料來源使用 DynamoDB 模組：  

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

export function request(ctx) {
	ddb.get({ key: { id: ctx.args.id } })
}
```

另一個範例是採用下列映射範本，將項目放入 Amazon DynamoDB 資料來源中：

```
{
    "operation" : "PutItem",
    "key" : {
        "id": $util.dynamodb.toDynamoDBJson($util.autoId()),
    },
    "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args)
}
```

評估時，此映射範本字串必須產生有效的 JSON 編碼字串。使用 JavaScript 時，您的程式碼會直接傳回請求物件：

```
import { util } from '@aws-appsync/utils';
export function request(ctx) {
  const { id = util.autoId(), ...values } = ctx.args;
  return {
    operation: 'PutItem',
    key: util.dynamodb.toMapValues({ id }),
    attributeValues: util.dynamodb.toMapValues(values),
  };
}
```

評估為：

```
{
  "operation": "PutItem",
  "key": {
    "id": { "S": "2bff3f05-ff8c-4ed8-92b4-767e29fc4e63" }
  },
  "attributeValues": {
    "firstname": { "S": "Shaggy" },
    "age": { "N": 4 }
  }
}
```

**注意**  
我們建議您搭配 DynamoDB 資料來源使用 DynamoDB 模組：  

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

export function request(ctx) {
	const { id = util.autoId(), ...item } = ctx.args
	return ddb.put({ key: { id }, item })
}
```

# 在直接資料來源存取和透過 Lambda 資料來源代理之間進行選擇
<a name="choosing-data-source"></a>

透過 AWS AppSync 和`APPSYNC_JS`執行時間，您可以使用 AWS AppSync 函數存取資料來源，撰寫自己的程式碼來實作自訂商業邏輯。這可讓您輕鬆地直接與資料來源互動，例如 Amazon DynamoDB、Aurora Serverless、OpenSearch Service、HTTP APIs 和其他 AWS 服務，而無需部署額外的運算服務或基礎設施。 AWS AppSync 也可透過設定 Lambda 資料來源，輕鬆與 AWS Lambda 函數互動。Lambda 資料來源可讓您使用 AWS Lambda的完整集功能來執行複雜的商業邏輯，以解決 GraphQL 請求。在大多數情況下，直接連接到其目標資料來源的 an AWS AppSync 函數將提供您需要的所有功能。在您需要實作`APPSYNC_JS`執行時間不支援的複雜商業邏輯的情況下，您可以使用 Lambda 資料來源做為代理來與目標資料來源互動。


|  |  |  | 
| --- |--- |--- |
|  | 直接資料來源整合 | Lambda 資料來源做為代理 | 
| 使用案例 | AWS AppSync functions interact directly with API data sources. | AWS AppSync functions call Lambdas that interact with API data sources. | 
| Runtime | APPSYNC\$1JS (JavaScript) | 任何支援的 Lambda 執行時間 | 
| Maximum size of code | per AWS AppSync 函數 32，000 個字元 | 每個 Lambda 50 MB （壓縮，用於直接上傳） | 
| External modules | 有限 - 僅限 APPSYNC\$1JS 支援的功能 | 是 | 
| Call any AWS service | 是 - Using AWS AppSync HTTP 資料來源 | 是 - 使用 AWS SDK | 
| Access to the request header | 是 | 是 | 
| Network access | 否 | 是 | 
| File system access | 否 | 是 | 
| Logging and metrics | 是 | 是 | 
| Build and test entirely within AppSync | 是 | 否 | 
| Cold start | 否 | 否 - 使用佈建並行 | 
| Auto-scaling | 是 - 透明地 by AWS AppSync | 是 - 如 Lambda 中所設定 | 
| Pricing | 不收取其他費用 | 按 Lambda 用量收費 | 

直接與其目標資料來源整合的AWS AppSync 函數非常適合下列使用案例：
+  與 Amazon DynamoDB、Aurora Serverless 和 OpenSearch Service 互動
+  與 HTTP APIs 互動並傳遞傳入標頭 
+  使用 HTTP 資料來源與 AWS 服務互動 （使用提供的資料來源角色 AWS AppSync 自動簽署請求） 
+  在存取資料來源之前實作存取控制 
+  在履行請求之前，實作擷取資料的篩選 
+  在解析程式管道中以循序執行 AWS AppSync 函數來實作簡單的協同運作 
+  在查詢和變動中控制快取和訂閱連線。

使用 Lambda 資料來源做為代理的AWS AppSync 函數非常適合下列使用案例：
+  使用 JavaScript 或速度範本語言 (VTL) 以外的語言 
+  調整和控制 CPU 或記憶體以最佳化效能 
+  在 中匯入第三方程式庫或需要不支援的功能 `APPSYNC_JS` 
+  提出多個網路請求和/或取得檔案系統存取權以滿足查詢 
+  使用批次處理[組態批次處理](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-lambda-js.html)請求。