

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# AWS AppSync JavaScript リゾルバーの概要
<a name="resolver-reference-overview-js"></a>

AWS AppSync では、データソースに対してオペレーションを実行して GraphQL リクエストに応答できます。クエリ、ミューテーション、サブスクリプションなど、実行する GraphQL フィールドごとに、リゾルバーをアタッチする必要があります。

リゾルバーは GraphQL とデータソースの間のコネクタです。受信した GraphQL リクエストをバックエンドデータソースの手順に変換する方法と、そのデータソースからのレスポンスを GraphQL レスポンスに変換する方法を AWS AppSync に伝えます。 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>

パイプラインリゾルバーのリクエストハンドラー (before step) では、定義した関数を実行する前に準備ロジックを実行できます。

### 関数のリスト
<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>

2 つの関数で構成されるパイプラインリゾルバーがあるとします。以下のリストでは、リゾルバーが呼び出されたときの実行フローを表しています。

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/ja_jp/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 インスタンスは 1 つのリゾルバーの実行を通して存続します。つまり、stash を使用して、リクエストとレスポンスのハンドラー間、およびパイプラインリゾルバーの関数間で、任意のデータを渡すことができます。stash は通常の JavaScript オブジェクトと同じようにテストできます。

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

`ctx.prev.result` は、パイプラインで実行された前のオペレーションの結果を表します。前のオペレーションがパイプラインリゾルバーリクエストハンドラーであった場合、`ctx.prev.result` はチェーン内の最初の関数に使用可能になります。前のオペレーションが最初の関数であった場合、`ctx.prev.result` は最初の関数の出力を表し、パイプライン内の 2 番目の関数に使用可能になります。前のオペレーションが最後の関数であった場合、`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 関数を使用すると、スキーマ内の複数のリゾルバー間で再利用できる一般的なロジックを記述できます。例えば、Amazon DynamoDB データソースからの項目のクエリを担当する `QUERY_ITEMS` という名前の one AWS AppSync 関数を使用できます。項目をクエリするリゾルバーについては、リゾルバーのパイプラインに関数を追加し、使用するクエリインデックスを指定するだけです。ロジックを再実装する必要はありません。

## 補足トピック
<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>

次の GraphQL クエリを使用して、Amazon DynamoDB データソースから `Post` 型を返す `getPost(id:ID!)` という名前のフィールドにパイプラインリゾルバーをアタッチするとします。

```
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`関数のリクエストハンドラーは DynamoDB モジュールが提供する utils AWS AppSyncを使用して、 をキー`id`として使用して`DynamoDBGetItem`リクエストを作成します。 は適切な`GetItem`オペレーション`ddb.get({ key: { id } })`を生成します。

```
{
    "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`ランタイムを使用したリゾルバーの開発に役立つ 2 つのライブラリが用意されています。
+ `@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`は、`APPSYNC_JS` ランタイムを利用する際にコード内の無効な構文を検出する ESLint プラグインです。このプラグインを使用すると、変更をクラウドにプッシュしなくても、開発中にコードに関するフィードバックを迅速に得ることができます。

`@aws-appsync/eslint-plugin` には、開発中に使用できる 2 つのルールセットが用意されています。

**"plugin:@aws-appsync/base"** は、プロジェクトで活用できる基本ルールセットを設定します。


| ルール | 説明 | 
| --- | --- | 
| 非同期 | 非同期のプロセスと Promise はサポートされていません。 | 
| no-await | 非同期のプロセスと Promise はサポートされていません。 | 
| no-classes | ルールはサポートされていません。 | 
| no-for | for はサポートされていない (サポートされている for-in および for-of は除く) | 
| no-continue | continue はサポートされていません。 | 
| no-generators | ジェネレータはサポートされていません。 | 
| no-yield | yield はサポートされていません。 | 
| no-labels | ラベルはサポートされていません。 | 
| no-this | this キーワードはサポートされていません。 | 
| no-try | try/catch 構造はサポートされていません。 | 
| no-while | while ループはサポートされていません。 | 
| no-disallowed-unary-operators | \$1\$1、-- および \$1 単項演算子は使用できません。 | 
| no-disallowed-binary-operators | instanceof 演算子は使用できません。 | 
| no-promise | 非同期のプロセスと Promise はサポートされていません。 | 

**"plugin:@aws-appsync/recommended"** にはいくつかの追加のルールがありますが、プロジェクトに TypeScript 構成を追加する必要もあります。


| ルール | 説明 | 
| --- | --- | 
| no-recursion | 再帰的な関数呼び出しは許可されません。 | 
| 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)」のインストールと使用手順に従ってください。次に、プロジェクトパッケージマネージャー (npm、yarn、pnpm など) を使用してプロジェクトに[プラグイン](https://www.npmjs.com/package/@aws-appsync/eslint-plugin)をインストールします。

```
$ 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 コードをローカルで記述し、`APPSYNC_JS` ランタイムで使用する前に JavaScript にトランスパイルできます。このプロセスは、TypeScript のインストールと `APPSYNC_JS` 環境の tsconfig.json の設定から始まります。その後、esbuild などのバンドルツールを使用して、コードをコンパイルしてバンドルできます。Amplify CLI は GraphQL スキーマからタイプを生成し、リゾルバーコードでこれらのタイプを使用できます。

リゾルバーと関数コードでは、`APPSYNC_JS` 要件を満たす限り、カスタムライブラリと外部ライブラリの両方を活用できます。バンドルツールは、コードを 1 つのファイルに結合して使用します AWS AppSync。ソースマップを含めると、デバッグに役立ちます。

## ライブラリの活用とコードのバンドル
<a name="using-external-libraries"></a>

リゾルバーと関数コードでは、`APPSYNC_JS` 要件を満たす限り、カスタムライブラリと外部ライブラリの両方を活用できます。これにより、アプリケーション内の既存のコードを再利用できます。複数のファイルで定義されたライブラリを使用するには、[esbuild](https://esbuild.github.io/) などのバンドルツールを使用してコードを 1 つのファイルに結合し、リ 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 が開発したプログラミング言語で、TypeScript タイピングシステムとともに JavaScript のすべての機能を備えています。TypeScript を使用すると、タイプセーフなコードを記述し、ビルド時にコードを AWS AppSyncに保存する前にエラーやバグを検出できます。`@aws-appsync/utils` パッケージは完全に型指定されています。

`APPSYNC_JS` ランタイムは TypeScript を直接サポートしていません。コードを AWS AppSyncに保存する前に、まず TypeScript コードを `APPSYNC_JS` ランタイムがサポートする JavaScript コードにトランスパイルする必要があります。TypeScript を使用してローカル統合開発環境 (IDE) にコードを記述できますが、 AWS AppSync コンソールで TypeScript コードを作成することはできません。

開始する前に、プロジェクトに [TypeScript](https://www.typescriptlang.org/download) がインストールされていることを確認してください。次に、[TSConfig](https://www.typescriptlang.org/tsconfig) を使用して `APPSYNC_JS` ランタイムと連携するように TypeScript のトランスコンパイル設定を構成します。使用できる基本 `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
```

特定の状況 (スキーマの更新時など) で codegen を再生成するには、以下のコマンドを実行します。

```
$ 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` プラグインをインポートすることで、バンドルを自動的にリントできます。その後、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` はコードの最後に表示する必要があります。以下の形式の 1 行のコメントで定義されます。

```
//# 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` を `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/ja_jp/appsync/latest/devguide/images/cloudwatch-sourcemap.jpeg)


CloudWatch ログのエントリを見ると、2 つのファイルの機能がバンドルされ、同時に実行されていることがわかります。各ファイルの元のファイル名もログにはっきりと反映されています。

# でのリゾルバーと関数ハンドラーのテスト 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 SDK](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 関数を使用してデータソースにアクセスすることで、カスタムビジネスロジックを実装する独自のコードを記述できます。これにより、追加の計算 AWS サービスやインフラストラクチャをデプロイすることなく、Amazon DynamoDB、Aurora Serverless、OpenSearch Service、HTTP APIs、その他の サービスなどのデータソースと直接やり取りすることが容易になります。 AWS AppSync では、Lambda データソースを設定することで、 AWS Lambda 関数の操作も簡単です。Lambda データソースを使用すると、 AWS Lambdaのフルセット機能を使用して複雑なビジネスロジックを実行し、GraphQL リクエストを解決できます。ほとんどの場合、ターゲットデータソースに直接接続された 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 |  AWS AppSync 関数あたり 32,000 文字 | 50 MB (zip 圧縮済み、直接アップロード) | 
| External modules | 制限あり-APPSYNC\$1JS がサポートしている機能のみ | はい | 
| Call any AWS service | はい - 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 | いいえ | No - プロビジョニング済み同時実行 | 
| Auto-scaling | はい - AWS AppSync によって透過的に | Yes - Lambda で設定されているとおり | 
| Pricing | 追加料金なし | Lambda の使用に対して課金 | 

ターゲットデータソースと直接統合するAWS AppSync 関数は、次のようなユースケースに最適です。
+  Amazon DynamoDB、Aurora サーバーレス、OpenSearch サービスとのやり取り
+  HTTP API とのやりとりと受信ヘッダーの受け渡し 
+  HTTP データソースを使用して AWS サービスとやり取りする (指定されたデータソースロールを使用してリクエスト AWS AppSync に自動的に署名する) 
+  データソースにアクセスする前のアクセス制御の実装 
+  リクエストに応答する前に、取得したデータをフィルター処理する。
+  リゾルバーパイプラインでの AWS AppSync 関数のシーケンシャル実行によるシンプルなオーケストレーションの実装 
+  クエリとミューテーションにおけるキャッシュ接続とサブスクリプション接続の制御。

Lambda データソースをプロキシとして使用するAWS AppSync 関数は、次のようなユースケースに最適です。
+  JavaScript または Velocity TL (VTL) 以外の言語を使用する 
+  CPU またはメモリの調整と制御によるパフォーマンスの最適化 
+  サードパーティ製ライブラリのインポートまたは `APPSYNC_JS` でサポートされていない機能の使用が必要 
+  複数のネットワークリクエストを行ったり、クエリを実行するためにファイルシステムにアクセスしたりする 
+  [バッチ設定](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-reference-lambda-js.html)を使用してリクエストをバッチ処理する。