

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

# でのリアルタイムデータアプリケーションのサブスクリプションの使用 AWS AppSync
<a name="aws-appsync-real-time-data"></a>

**重要**  
2025 年 3 月 13 日以降、 AWS AppSync Events を使用して WebSockets を搭載したリアルタイム PubSub API を構築できます。詳細については、「*AWS AppSync Events デベロッパーガイド*」の「[WebSocket 経由でイベントを公開する](https://docs.aws.amazon.com/appsync/latest/eventapi/publish-websocket.html)」を参照してください。

AWS AppSync では、サブスクリプションを利用して、ライブアプリケーションの更新、プッシュ通知などを実装できます。クライアントが GraphQL サブスクリプションオペレーションを呼び出すと、 AWS AppSync によって安全な WebSocket 接続が自動的に確立され、維持されます。その後、アプリケーションはデータソースからサブスクライバーにデータをリアルタイムで配信でき、 AWS AppSync はアプリケーションの接続とスケーリング要件を継続的に管理します。以下のセクションでは、 AWS AppSync のサブスクリプションの仕組みを示します。

## GraphQL スキーマサブスクリプションディレクティブ
<a name="graphql-schema-subscription-directives"></a>

 AWS AppSync のサブスクリプションは、ミューテーションへの応答として呼び出されます。つまり、ミューテーションに GraphQL スキーマディレクティブを指定することで、 AWS AppSync のデータソースをリアルタイムで作成できます。

 AWS Amplify クライアントライブラリは、サブスクリプション接続管理を自動的に処理します。ライブラリは純粋な WebSockets をクライアントとサービス間のネットワークプロトコルとして使用します。

**注記**  
サブスクリプションへの接続時に認可を制御するには、 AWS Identity and Access Management (IAM) AWS Lambda、、Amazon Cognito ID プール、または Amazon Cognito ユーザープールを使用して、フィールドレベルの認可を行うことができます。サブスクリプションのきめ細かなアクセスコントロールの場合、リゾルバーをサブスクリプションフィールドにアタッチし、発信者と AWS AppSync データソースの ID を使用してロジックを実行できます。詳細については、「[GraphQL API を保護するための認可と認証の設定](security-authz.md)」を参照してください。

サブスクリプションはミューテーションからトリガーされ、ミューテーション選択セットが受信者に送信されます。

次の例では、GraphQL サブスクリプションの操作方法を示します。データソースを指定しません。これは、データソースが 、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
    }
}
```

このサブスクリプションクエリは、クライアント接続とツールに必要です。

ピュアな WebSocket クライアントを使用する場合、各クライアントが独自の選択セットを定義できるため、選択セットのフィルタリングはクライアントごとに行われます。この場合、サブスクリプション選択セットは、ミューテーション選択セットのサブセットである必要があります。例えば、サブスクリプションが `addedPost{author title}` ミューテーションにリンクされていると、`addPost(...){id author title url version}` 投稿の作成者とタイトルのみを受け取ります。他のフィールドは受け取りません。ただし、ミューテーションの選択セットに作成者が欠けていた場合、サブスクライバーは作成者フィールドに対して `null` 値を取得します (または、スキーマ内で作成者フィールドが required/not-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` フィールドの戻り値の型は、対応する mutation フィールドの戻り値の型に一致する必要があります。前の例では、これが `addPost` と `addedPost` の両方が `Post` タイプとして返され、表示されます。

クライアントでサブスクリプションをセットアップするには、「[Amplify クライアントを使用したクライアントアプリケーションの構築](building-a-client-app.md)」を参照してください。

## サブスクリプション引数の使用
<a name="using-subscription-arguments"></a>

GraphQL サブスクリプションを使用する上で重要なのは、引数をいつ、どのように使うかを理解することです。微妙な変更を加えることで、発生したミューテーションをクライアントに通知する方法とタイミングを変更できます。そのためには、クイックスタートの章にある「Todos」を作成するサンプルスキーマを参照してください。このサンプルスキーマでは、以下のミューテーションが定義されます。

```
type Mutation {
    createTodo(input: CreateTodoInput!): Todo
    updateTodo(input: UpdateTodoInput!): Todo
    deleteTodo(input: DeleteTodoInput!): Todo
}
```

デフォルトのサンプルでは、クライアントは引数なしで `onUpdateTodo` `subscription` を使うことで、任意の `Todo` への更新を購読できます。

```
subscription OnUpdateTodo {
  onUpdateTodo {
    description
    id
    name
    when
  }
}
```

引数を使用して `subscription` をフィルタリングできます。例えば、特定の `ID` を含む `todo` が更新された場合に `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>

 AWS AppSync でサブスクリプションクエリを作成する場合、`null`引数の値は引数を完全に省略するのとは異なる方法で結果をフィルタリングします。

todo を作成できる todos API サンプルに戻りましょう。クイックスタートの章にあるサンプルスキーマを参照してください。

スキーマを変更して、所有者が誰であるかを記述する新しい `owner` フィールドを `Todo` タイプに追加してみましょう。`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 は API の GraphQL サブスクリプションのプロトコルとして利用できなくなりました。 AWS AppSync APIs Pure WebSockets は、 でサポートされている唯一のプロトコルです AWS AppSync。**  
2019 年 11 月以降にリリースされた AWS AppSync SDK または Amplify ライブラリに基づくクライアントは、デフォルトで純粋な WebSocketsを自動的に使用します。クライアントを最新バージョンにアップグレードすると、 AWS AppSyncクライアントは純粋な WebSockets エンジンを使用できます。  
純粋な WebSockets には、より大きなペイロードサイズ (240KB)、幅広いクライアントオプション、改善された CloudWatch メトリックスが付属しています。純粋な WebSocket クライアントを使用する方法の詳細については、「[ AWS AppSync でのリアルタイム WebSocket クライアントの構築](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 を構築できます。詳細については、「*AWS AppSync Events デベロッパーガイド*」の「[WebSocket 経由でイベントを公開する](https://docs.aws.amazon.com/appsync/latest/eventapi/publish-websocket.html)」を参照してください。

一部のアプリケーションでは、クライアントが特定のチャネルまたはトピックをリスンする単純な WebSocket API のみが必要です。特定の形式や厳密に型指定された要件のない汎用 JSON データを、純粋でシンプルなパブリッシュ/サブスクライブ (pub/sub) パターンで、これらのチャネルのいずれかをリスニングしているクライアントにプッシュできます。

 AWS AppSync を使用して、APIs バックエンドとクライアント側の両方で GraphQL コードを自動的に生成することで、GraphQL の知識がほとんどまたはまったくないシンプルな pub/sub WebSocket API を数分で実装します。

## Pub/sub API を作成して設定する
<a name="aws-appsync-real-time-enhanced-filtering-using-pub-sub-apis"></a>

開始するには、次のことを行います。

1. にサインイン AWS マネジメントコンソール し、[AppSync コンソール](https://console.aws.amazon.com/appsync/)を開きます。

   1. **ダッシュボード**で、**[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 バックエンドとやり取りするためのシンプルな抽象化を提供します。これには、AppSync リアルタイム WebSocket プロトコルと完全に互換性がある組み込み 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. リアルタイムデータの送受信をテストするには、2 つのブラウザーウィンドウを開いて *localhost:3000* にアクセスします。サンプルアプリケーションは、一般的な JSON データを *robots* という名前のハードコードされたチャネルに送信するように設定されています。

1.  ブラウザウィンドウの 1 つで、テキストボックスに次の JSON blob を入力し、**[送信]** をクリックします。

   ```
   {
     "robot":"r2d2",
     "planet": "tatooine"
   }
   ```

どちらのブラウザーインスタンスも *robots* チャンネルに登録され、ウェブアプリケーションの下部に表示される公開データをリアルタイムで受信します。

![\[例: Pub/sub API 用 React アプリ\]](http://docs.aws.amazon.com/ja_jp/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 API の実装
<a name="aws-appsync-real-time-enhanced-filtering-existing-apps"></a>

既存のアプリケーションにリアルタイム機能を実装するだけであれば、この汎用的な pub/sub API 構成をあらゆるアプリケーションや API テクノロジーに簡単に統合できます。単一の API エンドポイントを使用して、GraphQL を使用した 1 回のネットワーク呼び出しで 1 つ以上のデータソースのデータに安全にアクセスし、操作し、組み合わせる利点がありますが、 AWS AppSync のリアルタイム機能を活用するために既存の REST ベースのアプリケーションをゼロから変換または再構築する必要はありません。例えば、既存の CRUD ワークロードを別の API エンドポイントに配置し、クライアントは既存のアプリケーションから汎用 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 を構築できます。詳細については、「*AWS AppSync Events デベロッパーガイド*」の「[WebSocket 経由でイベントを公開する](https://docs.aws.amazon.com/appsync/latest/eventapi/publish-websocket.html)」を参照してください。

では 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、チケット管理システム API を定義する次の GraphQL スキーマを例として使用します。

```
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` というリストにまとめることができます。フィルターは、それぞれフィールド、演算子、値を含む少なくとも 1 つのルールを使用して定義されます。拡張フィルターを設定するための `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`\$1

OR 
+ `classification` チケットを`Security`に設定 

  AND 
+ `group`アサインを`admin`または`operators`に設定

![\[例: チケットフィルタリングクエリの表示例\]](http://docs.aws.amazon.com/ja_jp/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` でユーザーに関する情報を取得できます。この情報を使用して、ユーザーの ID に基づいてフィルタを設定できます。

次に、拡張されたフィルタ動作を `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` がネストレベル 1、`address` がネストレベル 2、`country` がネストレベル 3 を表しており、これらはすべて `.` セパレータで区切られています。

このサブスクリプションは、`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 レベルのネストをサポートしています。ネストレベル 5 を超えるスキーマフィールドのフィルターは無視されます。以下の GraphQL レスポンスを見てください。`venue.address.country.metadata.continent` の `continent` フィールドはレベル 5 のネストなので許可されています。ただし、`venue.address.country.metadata.capital.financial` の `financial` はレベル 6 のネストなので、フィルターは機能しません。

  ```
  {
      "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 を構築できます。詳細については、「*AWS AppSync Events デベロッパーガイド*」の「[WebSocket 経由でイベントを公開する](https://docs.aws.amazon.com/appsync/latest/eventapi/publish-websocket.html)」を参照してください。

では 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 と一致する ID が含まれている場合、対応するサブスクリプションはサブスクライブ解除されます。さらに、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 が次のサブスクリプションリクエストを使用して、その ID `group-1` を持つ新しいユーザーを ID `user-1` のグループにサブスクライブするとします。

```
onGroupMessageCreated(userId : "user-1", groupId: :"group-1"){...}
```

AWS AppSync はサブスクリプションリゾルバーを実行します。これにより、前述の`onGroupMessageCreated`レスポンスマッピングテンプレートで定義されているサブスクリプションフィルターと無効化フィルターが生成されます。クライアント A の場合、サブスクリプションフィルタはへのデータ送信のみを許可し`group-1`、無効化フィルタは `user-1` と `group-1` の両方に定義されます。

ここで、クライアント B が次のサブスクリプションリクエストを使用して、その ID `user-2` を持つユーザーをその ID `group-2`のグループにサブスクライブすると仮定します。

```
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 はメッセージを受信します。ただし、ユーザーは `group-1` に参加していないため、クライアント B はメッセージを受信しません。また、リクエストはサブスクリプションリゾルバーで定義されているサブスクリプションフィルターと一致しません。

最後に、`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)を使用して特定のデータにアクセスできます。

例えば、ミューテーションの無効化ペイロードとして E メールアドレスを設定し、そのアドレスを Amazon Cognito ユーザープールまたは OpenID Connect で認証されたサブスクライブユーザーからのメール属性またはクレームと照合することができます。`extensions.setSubscriptionInvalidationFilter()` サブスクリプション無効化ツールで定義された無効化フィルターは、ミューテーションの `extensions.invalidateSubscriptions()` ペイロードによって設定されたメールアドレスが、`context.identity.claims.email` でユーザーの JWT トークンから取得したメールアドレスと一致するかどうかを確認し、無効化を開始します。

# AWS AppSync でのリアルタイム WebSocket クライアントの構築
<a name="real-time-websocket-client"></a>

**重要**  
2025 年 3 月 13 日以降、 AWS AppSync Events を使用して WebSockets を搭載したリアルタイム PubSub API を構築できます。詳細については、「*AWS AppSync Events デベロッパーガイド*」の「[WebSocket 経由でイベントを公開する](https://docs.aws.amazon.com/appsync/latest/eventapi/publish-websocket.html)」を参照してください。

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/ja_jp/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`メッセージを待機します。このメッセージには、`"ka"` (キープアライブ) メッセージの最大待機時間 (ミリ秒) である `connectionTimeoutMs` パラメータが含まれています。

1. AWS AppSync は定期的に`"ka"`メッセージを送信します。クライアントは、各 `"ka"` メッセージを受信した時間を追跡します。クライアントが `connectionTimeoutMs` ミリ秒以内に `"ka"` メッセージを受信しない場合、クライアントは接続を終了する必要があります。

1. クライアントは、`start` サブスクリプションメッセージを送信してサブスクリプションを登録します。単一の WebSocket 接続では、異なる認可モードであっても、複数のサブスクリプションがサポートされます。

1. クライアントは、 AWS AppSync が成功したサブスクリプションを確認するために`start_ack`メッセージを送信するのを待ちます。エラーが発生した場合、 AWS AppSync は`"type": "error"`メッセージを返します。

1. クライアントは、対応するミューテーションが呼び出された後に送信されるサブスクリプションイベントを監視します。クエリとミューテーションは通常、 AWS AppSync GraphQL エンドポイント`https://`に送信されます。サブスクリプションは、安全な WebSocket () を使用して AWS AppSync リアルタイムエンドポイントを経由します`wss://`。

1. クライアントは、`stop` サブスクリプションメッセージを送信してサブスクリプションを登録解除します。

1. すべてのサブスクリプションを登録解除した後、WebSocket を介して転送されるメッセージがないことを確認した後、クライアントは WebSocket 接続から切断できます。

## WebSocket 接続を確立するためのハンドシェイクの詳細
<a name="handshake-details-to-establish-the-websocket-connection"></a>

 AWS AppSync で正常なハンドシェイクに接続して開始するには、WebSocket クライアントに以下が必要です。
+  AWS AppSync リアルタイムエンドポイント
+ ヘッダー – AWS AppSync エンドポイントと認可に関連する情報が含まれています。 AWS AppSync は、ヘッダーを提供する次の 3 つの方法をサポートしています。
  + クエリ文字列を使用するヘッダー
    + ヘッダー情報は、文字列化された JSON オブジェクトから派生した base64 文字列としてエンコードされます。この JSON オブジェクトには、 AWS AppSync エンドポイントと認可に関連する詳細が含まれています。JSON オブジェクトのコンテンツは、認可モードによって異なります。
  + `Sec-WebSocket-Protocol` 経由のヘッダー
    +  AWS AppSync エンドポイントと認可に関連する情報を含む文字列化された JSON オブジェクトからの base64Url-encodedされた文字列は、`Sec-WebSocket-Protocol`ヘッダーのプロトコルとして渡されます。JSON オブジェクトのコンテンツは、認可モードによって異なります。
  + 標準 HTTP ヘッダー経由のヘッダー:
    + ヘッダーは、GraphQL クエリとミューテーションのヘッダーを AWS AppSync に渡す方法と同様に、接続リクエストで標準 HTTP ヘッダーとして渡すことができます。ただし、標準 HTTP ヘッダーを介してヘッダーを渡すことは、プライベート API 接続リクエストではサポートされていません。
+  `payload` – Base64 でエンコードされた `payload` の文字列。ペイロードは、クエリ文字列を使用してヘッダーが指定されている場合にのみ必要です

これらの必要な詳細情報を使用して、WebSocket クライアントは、WebSocket プロトコルとして `graphql-ws` を使用して、クエリ文字列がある API リアルタイムエンドポイントを含む URL に接続できます。

### 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://`) に接続できます。

カスタムドメイン名を使用すると、1 つのドメインを使用して両方のエンドポイントを操作できます。例えば、カスタムドメインとして `api.example.com` 設定すると、次の URL を使用して 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` と `x-api-key` を含む JSON オブジェクトが文字列に変換されます。次に、この文字列は base64 エンコードを使用してエンコードされます。結果の base64 エンコードされた文字列は、 AWS AppSync リアルタイムエンドポイントとの接続を確立するための `header` WebSocket URL に という名前のクエリパラメータとして追加されます。結果のリクエスト URL は次の形式です。

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql?header=eyJob3N0IjoiZXhhbXBsZTEyMzQ1Njc4OTAwMDAuYXBwc3luYy1hcGkudXMtZWFzdC0xLmFtYXpvbmF3cy5jb20iLCJ4LWFtei1kYXRlIjoiMjAyMDA0MDFUMDAxMDEwWiIsIngtYXBpLWtleSI6ImRhMi16NHc0NHZoczV6Z2MzZHRqNXNranJsbGxqaSJ9&payload=e30=
```

base64 でエンコードされたヘッダーオブジェクトに加えて、空の JSON オブジェクト \$1\$1 も base64 でエンコードされ、`payload` という名前の別のクエリパラメータとして WebSocket URL に含まれることに注意してください。

**`Sec-WebSocket-Protocol` 経由のヘッダー**

`host` と `x-api-key` を含む JSON オブジェクトは文字列に変換され、base64Url エンコードを使用してエンコードされます。結果の base64Url でエンコードされた文字列には、`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 接続を確立するときに、ホストと API キーの情報が標準の HTTP ヘッダーを使用して送信されます。結果のリクエスト 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 トークン。ヘッダーには [Bearer スキーム](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` と `Authorization` を含む JSON オブジェクトが文字列に変換されます。次に、この文字列は base64 エンコードを使用してエンコードされます。結果の base64 エンコードされた文字列は、 AWS AppSync リアルタイムエンドポイントとの接続を確立するための `header` WebSocket URL に という名前のクエリパラメータとして追加されます。結果のリクエスト URL は次の形式です。

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql?header=eyJBdXRob3JpemF0aW9uIjoiZXlKcmFXUWlPaUpqYkc1eGIzQTVlVzVNSzA5UVlYSXJNVEpIV0VGTFNYQmllVTVXTkhoc1FqaFBWVzlZTW5NMldsZHZQU0lzSW1Gc1p5STZJbEpUTWpVMkluMC5leUp6ZFdJaU9pSmhObU5tTWpjd055MHhOamd4TFRRMU5ESXRPV1l4T0MxbE5qWTBNVGcyTmpsa016WWlMQ0psZG1WdWRGOXBaQ0k2SW1Wa016TTVNbU5rTFdOallUTXROR00yT0MxaE5EWXlMVEpsWkdJM1pUTm1ZMkZqWmlJc0luUnZhMlZ1WDNWelpTSTZJbUZqWTJWemN5SXNJbk5qYjNCbElqb2lZWGR6TG1OdloyNXBkRzh1YzJsbmJtbHVMblZ6WlhJdVlXUnRhVzRpTENKaGRYUm9YM1JwYldVaU9qRTFOamswTlRjM01UZ3NJbWx6Y3lJNkltaDBkSEJ6T2x3dlhDOWpiMmR1YVhSdkxXbGtjQzVoY0MxemIzVjBhR1ZoYzNRdE1pNWhiV0Y2YjI1aGQzTXVZMjl0WEM5aGNDMXpiM1YwYUdWaGMzUXRNbDgzT0hZMFNWWmliVkFpTENKbGVIQWlPakUxTmprME5qRXpNakFzSW1saGRDSTZNVFUyT1RRMU56Y3lNQ3dpYW5ScElqb2lOVGd6WmpobVltTXRNemsyTVMwMFl6QTRMV0poWlRBdFl6UXlZMkl4TVRNNU5EWTVJaXdpWTJ4cFpXNTBYMmxrSWpvaU0zRmxhalZsTVhabU16ZDFOM1JvWld3MGRHOTFkREprTVd3aUxDSjFjMlZ5Ym1GdFpTSTZJbVZzYjNKNllXWmxJbjAuQjRjZEp0aDNLRk5wSjZpa1ZwN2U2RFJlZTk1VjZRaS16RUUyREpIN3NIT2wyenhZaTdmLVNtRUdvaDJBRDhlbXhRUllhakJ5ei1yRTRKaDBRT3ltTjJZcy1aSWtNcFZCVFBndS1UTVdEeU9IaERVbVVqMk9QODJ5ZVozd2xaQXRyX2dNNEx6alhVWG1JX0syeUdqdVhmWFRhYTFtdlFFQkcwbVFmVmQ3U2Z3WEItamN2NFJZVmk2ajI1cWdvdzlFdzUydWZ1clBxYUstM1dBS0czMktwVjhKNC1XZWpxOHQwYy15QTdzYjhFbkI1NTFiN1RVOTN1S1JpVlZLM0U1NU5rNUFEUG9hbV9XWUU0NWkzczVxVkFQXy1Jblc3NU5Vb09DR1RzUzhZV01mYjZlY0hZSi0xai1iekEyN3phVDlWamN0WG45YnlORlptS0xwQTJMY3h3IiwiaG9zdCI6ImV4YW1wbGUxMjM0NTY3ODkwMDAwLmFwcHN5bmMtYXBpLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tIn0=&payload=e30=
```

base64 でエンコードされたヘッダーオブジェクトに加えて、空の JSON オブジェクト \$1\$1 も base64 でエンコードされ、`payload` という名前の別のクエリパラメータとして WebSocket URL に含まれることに注意してください。

**`Sec-WebSocket-Protocol` 経由のヘッダー**

`host` と `Authorization` を含む JSON オブジェクトは文字列に変換され、base64Url エンコードを使用してエンコードされます。結果の base64Url でエンコードされた文字列には、`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 で、YYYYMMDD'T'HHMMSS'Z' の ISO 8601 形式である必要があります。たとえば、20150830T123600Z は有効なタイムスタンプです。タイムスタンプにミリ秒を含めないでください。詳細については、*AWS 全般のリファレンス* で「[署名バージョン 4 で日付を扱う](https://docs.aws.amazon.com/general/latest/gr/sigv4-date-handling.html)」を参照してください。
  +  `"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 エンドポイント用の Signature Version 4 (SigV4) 署名情報。署名プロセスの詳細については、「*AWS 全般のリファレンス*」の「[タスク 4: HTTP リクエストに署名を追加する](https://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to-request.html)」を参照してください。

SigV4 署名の HTTP リクエストには、正規の URL が含まれています。これは AWS AppSync GraphQL エンドポイントに `/connect` が追加されたものです。サービスエンドポイント 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 エンコードされた文字列は、`header` という名前のクエリパラメータとして WebSocket URL に追加されます。結果のリクエスト URL は次の形式です。

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql?header=eyJBdXRob3JpemF0aW9uIjoiZXlKcmFXUWlPaUpqYkc1eGIzQTVlVzVNSzA5UVlYSXJNVEpIV0VGTFNYQmllVTVXTkhoc1FqaFBWVzlZTW5NMldsZHZQU0lzSW1Gc1p5STZJbEpUTWpVMkluMC5leUp6ZFdJaU9pSmhObU5tTWpjd055MHhOamd4TFRRMU5ESXRPV1l4T0MxbE5qWTBNVGcyTmpsa016WWlMQ0psZG1WdWRGOXBaQ0k2SW1Wa016TTVNbU5rTFdOallUTXROR00yT0MxaE5EWXlMVEpsWkdJM1pUTm1ZMkZqWmlJc0luUnZhMlZ1WDNWelpTSTZJbUZqWTJWemN5SXNJbk5qYjNCbElqb2lZWGR6TG1OdloyNXBkRzh1YzJsbmJtbHVMblZ6WlhJdVlXUnRhVzRpTENKaGRYUm9YM1JwYldVaU9qRTFOamswTlRjM01UZ3NJbWx6Y3lJNkltaDBkSEJ6T2x3dlhDOWpiMmR1YVhSdkxXbGtjQzVoY0MxemIzVjBhR1ZoYzNRdE1pNWhiV0Y2YjI1aGQzTXVZMjl0WEM5aGNDMXpiM1YwYUdWaGMzUXRNbDgzT0hZMFNWWmliVkFpTENKbGVIQWlPakUxTmprME5qRXpNakFzSW1saGRDSTZNVFUyT1RRMU56Y3lNQ3dpYW5ScElqb2lOVGd6WmpobVltTXRNemsyTVMwMFl6QTRMV0poWlRBdFl6UXlZMkl4TVRNNU5EWTVJaXdpWTJ4cFpXNTBYMmxrSWpvaU0zRmxhalZsTVhabU16ZDFOM1JvWld3MGRHOTFkREprTVd3aUxDSjFjMlZ5Ym1GdFpTSTZJbVZzYjNKNllXWmxJbjAuQjRjZEp0aDNLRk5wSjZpa1ZwN2U2RFJlZTk1VjZRaS16RUUyREpIN3NIT2wyenhZaTdmLVNtRUdvaDJBRDhlbXhRUllhakJ5ei1yRTRKaDBRT3ltTjJZcy1aSWtNcFZCVFBndS1UTVdEeU9IaERVbVVqMk9QODJ5ZVozd2xaQXRyX2dNNEx6alhVWG1JX0syeUdqdVhmWFRhYTFtdlFFQkcwbVFmVmQ3U2Z3WEItamN2NFJZVmk2ajI1cWdvdzlFdzUydWZ1clBxYUstM1dBS0czMktwVjhKNC1XZWpxOHQwYy15QTdzYjhFbkI1NTFiN1RVOTN1S1JpVlZLM0U1NU5rNUFEUG9hbV9XWUU0NWkzczVxVkFQXy1Jblc3NU5Vb09DR1RzUzhZV01mYjZlY0hZSi0xai1iekEyN3phVDlWamN0WG45YnlORlptS0xwQTJMY3h3IiwiaG9zdCI6ImV4YW1wbGUxMjM0NTY3ODkwMDAwLmFwcHN5bmMtYXBpLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tIn0=&payload=e30=
```

base64 でエンコードされたヘッダーオブジェクトに加えて、空の JSON オブジェクト \$1\$1 も base64 でエンコードされ、`payload` という名前の別のクエリパラメータとして WebSocket URL に含まれることに注意してください。

**`Sec-WebSocket-Protocol` 経由のヘッダー**

`host` およびその他の認可ヘッダーを含む JSON オブジェクトは文字列に変換され、base64Url エンコードを使用してエンコードされます。結果の base64Url でエンコードされた文字列には、`header-` というプレフィックスが付きます。このプレフィックス付き文字列は、 AWS AppSync リアルタイムエンドポイントとの WebSocket 接続を確立するときに、 `graphql-ws``Sec-WebSocket-Protocol`ヘッダーの に加えて新しいサブプロトコルとして使用されます。

結果のリクエスト 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=
```

**注記**  
1 つの WebSocket 接続には、(異なる認証モードであっても) 複数のサブスクリプションを設定できます。これを実装する 1 つの方法は、最初のサブスクリプション用の 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` と `Authorization` を含む JSON オブジェクトが文字列に変換されます。次に、この文字列は base64 エンコードを使用してエンコードされます。結果の base64 エンコードされた文字列は、 AWS AppSync リアルタイムエンドポイントとの接続を確立するための `header` WebSocket URL に という名前のクエリパラメータとして追加されます。結果のリクエスト URL は次の形式です。

```
wss://example1234567890000.appsync-realtime-api.us-east-1.amazonaws.com/graphql?header=eyJBdXRob3JpemF0aW9uIjoiZXlKcmFXUWlPaUpqYkc1eGIzQTVlVzVNSzA5UVlYSXJNVEpIV0VGTFNYQmllVTVXTkhoc1FqaFBWVzlZTW5NMldsZHZQU0lzSW1Gc1p5STZJbEpUTWpVMkluMC5leUp6ZFdJaU9pSmhObU5tTWpjd055MHhOamd4TFRRMU5ESXRPV1l4T0MxbE5qWTBNVGcyTmpsa016WWlMQ0psZG1WdWRGOXBaQ0k2SW1Wa016TTVNbU5rTFdOallUTXROR00yT0MxaE5EWXlMVEpsWkdJM1pUTm1ZMkZqWmlJc0luUnZhMlZ1WDNWelpTSTZJbUZqWTJWemN5SXNJbk5qYjNCbElqb2lZWGR6TG1OdloyNXBkRzh1YzJsbmJtbHVMblZ6WlhJdVlXUnRhVzRpTENKaGRYUm9YM1JwYldVaU9qRTFOamswTlRjM01UZ3NJbWx6Y3lJNkltaDBkSEJ6T2x3dlhDOWpiMmR1YVhSdkxXbGtjQzVoY0MxemIzVjBhR1ZoYzNRdE1pNWhiV0Y2YjI1aGQzTXVZMjl0WEM5aGNDMXpiM1YwYUdWaGMzUXRNbDgzT0hZMFNWWmliVkFpTENKbGVIQWlPakUxTmprME5qRXpNakFzSW1saGRDSTZNVFUyT1RRMU56Y3lNQ3dpYW5ScElqb2lOVGd6WmpobVltTXRNemsyTVMwMFl6QTRMV0poWlRBdFl6UXlZMkl4TVRNNU5EWTVJaXdpWTJ4cFpXNTBYMmxrSWpvaU0zRmxhalZsTVhabU16ZDFOM1JvWld3MGRHOTFkREprTVd3aUxDSjFjMlZ5Ym1GdFpTSTZJbVZzYjNKNllXWmxJbjAuQjRjZEp0aDNLRk5wSjZpa1ZwN2U2RFJlZTk1VjZRaS16RUUyREpIN3NIT2wyenhZaTdmLVNtRUdvaDJBRDhlbXhRUllhakJ5ei1yRTRKaDBRT3ltTjJZcy1aSWtNcFZCVFBndS1UTVdEeU9IaERVbVVqMk9QODJ5ZVozd2xaQXRyX2dNNEx6alhVWG1JX0syeUdqdVhmWFRhYTFtdlFFQkcwbVFmVmQ3U2Z3WEItamN2NFJZVmk2ajI1cWdvdzlFdzUydWZ1clBxYUstM1dBS0czMktwVjhKNC1XZWpxOHQwYy15QTdzYjhFbkI1NTFiN1RVOTN1S1JpVlZLM0U1NU5rNUFEUG9hbV9XWUU0NWkzczVxVkFQXy1Jblc3NU5Vb09DR1RzUzhZV01mYjZlY0hZSi0xai1iekEyN3phVDlWamN0WG45YnlORlptS0xwQTJMY3h3IiwiaG9zdCI6ImV4YW1wbGUxMjM0NTY3ODkwMDAwLmFwcHN5bmMtYXBpLnVzLWVhc3QtMS5hbWF6b25hd3MuY29tIn0=&payload=e30=
```

base64 でエンコードされたヘッダーオブジェクトに加えて、空の JSON オブジェクト \$1\$1 も base64 でエンコードされ、`payload` という名前の別のクエリパラメータとして WebSocket URL に含まれることに注意してください。

**`Sec-WebSocket-Protocol` 経由のヘッダー**

`host` と `Authorization` を含む JSON オブジェクトは文字列に変換され、base64Url エンコードを使用してエンコードされます。結果の base64Url でエンコードされた文字列には、`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`: オペレーションタイプに応じて、関連付けられたペイロード。

`id` フィールド `type` とフィールドはオプションで、`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。この 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 署名は、URL に `/connect` を追加する必要がなく、`data` は JSON 文字列化された GraphQL オペレーションに置き換えられます。次に、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 はミューテーションに関心のあるすべてのサブスクライバーを識別し、`"start"`サブスクリプションオペレーション`id`から対応するサブスクリプションを使用して各サブスクライバーに`"type":"data"`メッセージを送信します。クライアントは、データメッセージを受信したときに、対応するサブスクリプションと照合できるように、送信するサブスクリプション `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 から切断する前に、すべてのサブスクリプションを登録解除する必要があります。