

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

# GraphQL と AWS AppSync アーキテクチャ
<a name="graphql-overview"></a>

**注記**  
このガイドは、ユーザーが REST アーキテクチャスタイルに関する実用的な知識を持っていることを前提としています。GraphQL および AWS AppSyncを使用する前に、このトピックとその他のフロントエンドトピックを確認することをお勧めします。

GraphQL は API 用のクエリおよび操作言語です。GraphQL は、データ要件と相互作用を記述するための柔軟で直感的な構文を提供します。これにより、開発者は必要なものを正確に尋ねて、予測可能な結果を得ることができます。また、1 回のリクエストで多数のソースにアクセスできるようになるため、ネットワーク呼び出し回数と帯域幅要件が減り、バッテリー寿命と、アプリケーションが消費する CPU サイクルを節約できます。

データの更新はミューテーションによって簡単に行えるため、開発者はデータをどのように変更すべきかを説明できます。また、GraphQL はサブスクリプションによるリアルタイムソリューションの Quick Setup も容易にします。これらすべての機能と強力な開発者ツールを組み合わせることで、GraphQL はアプリケーションデータの管理に欠かせないものになっています。

GraphQL は REST に代わるものです。RESTful アーキテクチャは、現在、クライアントとサーバー間の通信において最もポピュラーなソリューションの 1 つです。リソース (データ) が URL によって公開されるという概念が中心になっています。これらの URL を使用すると `GET`、`POST`、`DELETE` などの HTTP メソッド形式の CRUD (作成、読み取り、更新、削除) 操作を通じてデータにアクセスし、データを操作できます。REST の利点は、学習と実装が比較的簡単であることです。RESTful API を素早く設定して、さまざまなサービスを呼び出すことができます。

しかし、テクノロジーはますます複雑になっています。アプリケーション、ツール、サービスが世界中のユーザー向けに拡大し始める中、高速でスケーラブルなアーキテクチャの必要性が最も重要になっています。スケーラブルな運用を扱う場合、REST には多くの欠点があります。例としてこの [ユースケース](https://aws.amazon.com/blogs/architecture/what-to-consider-when-modernizing-apis-with-graphql-on-aws/) を参照してください。

以下のセクションでは、RESTful API に関するいくつかの概念を確認します。次に、GraphQL とその仕組みを紹介します。

GraphQL の詳細と への移行の利点については AWS、[GraphQL 実装の決定ガイド](https://aws.amazon.com/graphql/guide/)」を参照してください。

**Topics**
+ [API とは](what-is-an-api.md)
+ [REST とは](what-is-rest.md)
+ [GraphQL とは](what-is-graphql.md)
+ [REST と GraphQL の比較](comparing-rest-graphql.md)
+ [REST よりも GraphQL を使用する理由](why-use-graphql.md)
+ [GraphQL API のコンポーネント](api-components.md)
+ [GraphQL の追加プロパティ](graphql-properties.md)

# API とは何ですか?
<a name="what-is-an-api"></a>

アプリケーションプログラミングインターフェイス (API) は、他のソフトウェアシステムと通信するために従わなければならないルールを定義します。開発者は API を公開または作成して、他のアプリケーションがプログラムによってアプリケーションと通信できるようにします。例えば、タイムシートアプリケーションでは、従業員のフルネームと日付範囲を尋ねる API を公開しています。この情報を受け取ると、従業員のタイムシートを内部で処理し、その日付範囲内の労働時間数を返します。

Web API は、クライアントとウェブ上のリソース間のゲートウェイと考えることができます。

## クライアント
<a name="what-is-a-client"></a>

クライアントはウェブ上の情報にアクセスしたいユーザーです。クライアントは、個人でも、API を使用するソフトウェアシステムでもかまいません。例えば、開発者は気象システムから気象データにアクセスするプログラムを作成できます。また、天気 Web サイトに直接アクセスしたときに、ブラウザから同じデータにアクセスすることもできます。

## リソース
<a name="what-is-a-resource"></a>

リソースは、さまざまなアプリケーションがクライアントに提供する情報です。リソースには、画像、動画、テキスト、数字、またはあらゆる種類のデータがあります。リソースをクライアントに提供するマシンはサーバーとも呼ばれます。組織は API を使用してリソースを共有し、セキュリティ、制御、認証を維持しながら Web サービスを提供します。さらに、API は、どのクライアントが特定の内部リソースにアクセスできるかを判断するのに役立ちます。

# REST とは?
<a name="what-is-rest"></a>

Representational State Transfer (REST) は、大まかに言うと API の動作に条件を課すソフトウェアアーキテクチャです。REST は当初、インターネットのような複雑なネットワーク上の通信を管理するためのガイドラインとして作成されました。REST ベースのアーキテクチャを使用すると、高性能で信頼性の高い通信を大規模にサポートできます。実装や変更が容易なため、あらゆる API システムの可視性とクロスプラットフォームの移植性を実現できます。

API 開発者は、複数の異なるアーキテクチャを使用して API を設計できます。REST アーキテクチャスタイルに従う API は REST API と呼ばれます。REST アーキテクチャを実装する Web サービスは RESTful Web サービスと呼ばれます。RESTful API という用語は、一般的に RESTful ウェブ API を指します。ただし、REST API と RESTful API という用語は同じ意味で使用できます。

REST アーキテクチャスタイルの原則は以下のとおりです。

## 統一インターフェース
<a name="uniform-interface"></a>

統一されたインターフェースは、あらゆる RESTful Web サービスの設計の基本です。これは、サーバーが情報を標準形式で転送することを示しています。フォーマットされたリソースは REST では表現と呼ばれます。この形式は、サーバーアプリケーション上のリソースの内部表現とは異なる場合があります。例えば、サーバーはデータをテキストとして保存し、HTML 表現形式で送信できます。

統一インターフェースにはアーキテクチャ上の制約が 4 つあります。

1.  リクエストではリソースを特定する必要があります。そのためには、統一されたリソース識別子を使用します。

1.  クライアントはリソース表現に十分な情報を持っており、必要に応じてリソースを変更または削除できます。サーバーは、リソースを詳しく説明するメタデータを送信することで、この条件を満たします。

1.  クライアントは、表現をさらに処理する方法に関する情報を受け取ります。サーバーは、クライアントがそれらを最適に使用する方法に関するメタデータを含むわかりやすいメッセージを送信することでこれを実現しています。

1.  クライアントは、タスクを完了するのに必要なその他すべての関連リソースに関する情報を受け取ります。サーバーは、クライアントがより多くのリソースを動的に見つけられるように、表現にハイパーリンクを送信することでこれを実現しています。

## ステートレス性
<a name="statelessness"></a>

REST アーキテクチャーにおけるステートレス性とは、サーバーが以前のすべての要求とは無関係にすべてのクライアント要求を完了させる通信方法を指します。クライアントは任意の順序でリソースをリクエストでき、すべてのリクエストはステートレスであるか、他のリクエストから分離されます。この REST API の設計上の制約は、サーバーが毎回リクエストを完全に理解して処理できることを意味します。

## 階層型システム
<a name="layered-system"></a>

階層型システムアーキテクチャでは、クライアントはクライアントとサーバー間の他の許可された仲介者に接続でき、それでもサーバーからの応答を受信します。サーバーは他のサーバーに要求を渡すこともできます。RESTful Web サービスは、セキュリティ、アプリケーション、ビジネスロジックなどの複数のレイヤーを持つ複数のサーバー上で動作し、連携してクライアントのリクエストに応えるように設計できます。これらの階層はクライアントには見えないままです。

## キャッシュ性
<a name="cacheability"></a>

RESTful な Web サービスはキャッシュをサポートします。キャッシュとは、サーバーの応答時間を短縮するために、一部の応答をクライアントまたは仲介者に保存するプロセスです。例えば、すべてのページに共通のヘッダーとフッターの画像がある Web サイトにアクセスしたとします。新しい Web サイトページにアクセスするたびに、サーバーは同じ画像を再送信する必要があります。これを避けるため、クライアントは最初の応答後にこれらの画像をキャッシュまたは保存し、キャッシュから直接画像を使用します。RESTful な Web サービスは、自身をキャッシュ可能またはキャッシュ不可と定義する API レスポンスを使用してキャッシュを制御します。

## RESTful API とは?
<a name="what-is-a-restful-api"></a>

RESTful API は、2 つのコンピューターシステムがインターネット上で安全に情報を交換するために使用するインターフェースです。ほとんどのビジネスアプリケーションは、さまざまなタスクを実行するために他の内部アプリケーションやサードパーティアプリケーションと通信する必要があります。例えば、毎月の給与明細を生成するには、内部会計システムが顧客の銀行システムとデータを共有して請求を自動化し、社内のタイムシートアプリケーションと通信する必要があります。RESTful API は、安全で信頼性が高く、効率的なソフトウェア通信標準に従っているため、このような情報交換をサポートします。

## RESTful API はどのように機能するのでしょうか?
<a name="how-do-restful-apis-work"></a>

RESTful API の基本的な機能は、インターネットを閲覧することと同じです。リソースが必要な場合、クライアントは API を使用してサーバーに接続します。API 開発者は、クライアントが REST API をどのように使用すべきかをサーバーアプリケーション API ドキュメントで説明しています。REST API コールの一般的な手順は次のとおりです。

1.  クライアントはリクエストをサーバーに送信します。クライアントは API ドキュメントに従い、サーバーが理解できる方法でリクエストをフォーマットします。

1.  サーバーはクライアントを認証し、クライアントにそのリクエストを行う権利があることを確認します。

1.  サーバーはリクエストを受け取り、内部で処理します。

1.  サーバーは、クライアントに対してレスポンスを返します。レスポンスには、リクエストが成功したかどうかをクライアントに伝える情報が含まれます。レスポンスには、クライアントがリクエストしたすべての情報も含まれます。

REST API のリクエストとレスポンスの詳細は、API 開発者が API をどのように設計したかによって若干異なります。

# GraphQL とは
<a name="what-is-graphql"></a>

GraphQL は API のクエリ言語であり、それらのクエリを実行するランタイムでもあります。GraphQL を使用すると、クライアントは必要なデータを正確にリクエストできるため、多くのシナリオで REST よりも柔軟で効率的な代替手段となります。事前定義されたエンドポイントに依存する REST とは異なり、GraphQL は 1 つのエンドポイントを使用し、クライアントはクエリとミューテーションの形式でデータ要件を指定できます。

GraphQL API の構造の詳細については、「[GraphQL API のコンポーネント](https://docs.aws.amazon.com/appsync/latest/devguide/api-components.html)」を参照してください。

# REST と GraphQL の比較
<a name="comparing-rest-graphql"></a>

API (アプリケーションプログラミングインターフェイス) は、アプリケーション間のデータ交換を容易にする上で重要な役割を果たします。前述のように、API を設計するための GraphQL と REST という 2 つの顕著なアプローチが登場しています。どちらもクライアントとサーバーの通信を可能にする基本的な目的を果たしますが、実装とユースケースでは大きく異なります。

GraphQL と REST には、いくつかの重要な特徴があります。

1. **クライアント/サーバーモデル**: どちらもデータ交換にクライアント/サーバーアーキテクチャを使用します。

1. **ステートレス**: どちらもリクエスト間でクライアントセッション情報を維持しません。

1. **HTTP ベース**: どちらも通常、基本となる通信プロトコルとして HTTP を使用します。

1. **リソース指向設計**: どちらも、クライアントが API を介してアクセスおよび操作できるデータまたはオブジェクトを参照するリソースに関するデータ交換を設計します。

1. **データ形式の柔軟性**: 両方で最も一般的に使用されるデータ交換形式は JSON ですが、XML や HTML などの他の形式もサポートされています。

1. **言語とデータベースに依存しない**: どちらも任意のプログラミング言語またはデータベース構造で動作するため、高い相互運用性があります。

1. **キャッシュサポート**: どちらもキャッシュをサポートしているため、クライアントとサーバーは頻繁にアクセスされるデータを保存してパフォーマンスを向上させることができます。

GraphQL と REST は、いくつかの基本原則を共有しながら、API 設計とデータフェッチに対するアプローチが大きく異なります。

1. **リクエスト構造とデータ取得**

   REST は、さまざまな HTTP メソッド (GET、POST、PUT、DELETE) を使用して、リソースに対してオペレーションを実行します。これには、多くの場合、異なるリソースに複数のエンドポイントが必要になるため、データの取得が非効率になる可能性があります。例えば、GET オペレーションを実行してユーザーのデータを取得すると、データのオーバーフェッチまたはアンダーフェッチが発生する可能性があります。正しいデータを取得するには、切り捨てまたは複数のオペレーションを呼び出すことができます。

   GraphQL は、すべてのオペレーションに単一のエンドポイントを使用します。データの取得にはクエリに依存し、データの変更にはミューテーションに依存します。クライアントはクエリを使用して、1 回のリクエストで必要なデータを正確に取得できるため、データ転送を最小限に抑えることでネットワークオーバーヘッドを削減できます。

1. **サーバー側のスキーマ**

   REST にはサーバー側のスキーマは必要ありませんが、効率的な API 設計とドキュメント化のためにオプションで定義できます。

   GraphQL は、厳密に型指定されたサーバー側のスキーマを使用して、データとデータサービスを定義します。GraphQL Schema Definition Language (SDL) で記述されたスキーマには、各オブジェクトのオブジェクトタイプとフィールド、および各フィールドのオペレーションを定義するサーバー側のリゾルバー関数が含まれます。

1. **バージョニング**

   REST には URL にバージョニングが含まれていることがよくあり、複数の API バージョンを同時に維持できます。バージョニングは必須ではありませんが、変更の中断を防ぐのに役立ちます。

   GraphQL は、下位互換性を必要とすることで、明示的なバージョニングなしで API の継続的な進化を促進します。削除されたフィールドはエラーメッセージを返し、非推奨タグは古いフィールドを段階的に廃止し、警告メッセージを返します。

1. **エラー処理** 

   REST はタイプが弱いため、エラー処理を周囲のコードに組み込む必要があります。これにより、タイプ関連のエラー (例: 数値をテキストとして解析) が自動的に識別されない場合があります。

   対照的に、GraphQL は強く入力され、包括的なスキーマ定義が必要です。これにより、サービスが多くのリクエストエラーを高い詳細レベルで自動的に識別できるようになります。

1. **ユースケース**

   REST は次の用途に適しています。
   + データ要件がそれほど複雑ではない小規模なアプリケーション。
   + データおよびオペレーションがすべてのクライアントで同様に使用されるシナリオ。
   + 複雑なデータクエリのニーズがないアプリケーション。

   GraphQL は次の用途に適しています。
   + リクエストとレスポンスを最小限に抑えることが重要な、帯域幅が限られているシナリオ。
   + 単一のエンドポイントで組み合わせる必要がある複数のデータソースを持つアプリケーション。
   + クライアントリクエストが大きく異なり、異なるレスポンス構造を期待する場合。

   GraphQL API と REST API の両方を 1 つのアプリケーション内で、さまざまな機能分野に使用できることに注意してください。さらに、完全な書き換えなしで GraphQL 機能を含めるように RESTful API をアップグレードできます。例については[、 AWS 「データソースの GraphQL リゾルバーを構築する](https://aws.amazon.com/graphql/resolvers/)方法」を参照してください。

# なぜ REST よりも GraphQL を使うのか？
<a name="why-use-graphql"></a>

REST はウェブ API の基本的なアーキテクチャスタイルの 1 つです。しかし、世界の相互接続が進むにつれて、堅牢でスケーラブルなアプリケーションを開発する必要性がより喫緊の課題となるでしょう。REST は現在、Web API を構築するための業界標準ですが、RESTful な実装には繰り返し発生するいくつかの欠点があることが確認されています。

1. **データリクエスト**: RESTful API を使用する場合、通常はエンドポイントを通じて必要なデータをリクエストします。この問題は、データがきちんとパッケージ化されていない場合に発生します。必要なデータが複数の抽象レイヤーに隠れている場合があり、データを取得する唯一の方法は複数のエンドポイントを使用することです。つまり、すべてのデータを抽出するために複数のリクエストを行うということです。

1. **オーバーフェッチとアンダーフェッチ**: 複数のリクエストの問題に加えて、各エンドポイントからのデータは厳密に定義されています。つまり、技術的に必要でなくても、その API に定義されているデータはすべて返されるということです。

   その結果、*オーバーフェッチが発生し*、リクエストから余分なデータが返されることになります。例えば、会社の人事データをリクエストしていて、特定の部門の従業員の名前を知りたいとします。データを返すエンドポイントには名前が含まれますが、役職や生年月日などの他のデータも含まれる場合があります。API は固定されているため、名前だけをリクエストすることはできません。残りのデータはそれに付随します。

   これとは逆に、十分なデータが返されない状況を*アンダーフェッチ*と呼びます。リクエストされたデータをすべて取得するには、サービスに対して複数のリクエストを行う必要がある場合があります。データの構造によっては、非効率的なクエリに遭遇し、恐ろしい n\$11 問題のような問題が発生する可能性があります。

1. **開発の反復に時間がかかる**: 多くの開発者は、アプリケーションのフローに合わせて RESTful API を調整しています。ただし、アプリケーションが大きくなるにつれて、フロントエンドとバックエンドの両方に大幅な変更が必要になる可能性があります。その結果、API はもはや効率的でも影響力のある形でもデータの形状に適合しなくなる可能性があります。その結果、API を変更する必要があるため、製品のイテレーションが遅くなります。

1. **大規模環境でのパフォーマンス**: こうした複合的な問題により、スケーラビリティが影響を受ける分野は多数あります。リクエストから返されるデータが多すぎる、または少なすぎる (結果的にリクエストが増える) ため、アプリケーション側のパフォーマンスが影響を受ける可能性があります。どちらの状況でも、ネットワークに不必要な負荷がかかり、パフォーマンスが低下します。開発者側では、API が固定され、リクエストしているデータに適合しなくなるため、開発速度が低下する可能性があります。

GraphQL のセールスポイントは、REST の欠点を克服することです。GraphQL が開発者に提供する主なソリューションは以下のとおりです。

1. **単一エンドポイント**: GraphQL は単一のエンドポイントを使用してデータをクエリします。データの形状に合わせて複数の API を構築する必要はありません。その結果、ネットワークを経由するリクエストが少なくなります。

1. **フェッチ**: GraphQL は、必要なデータを定義するだけで、オーバーフェッチとアンダーフェッチという長年の問題を解決します。GraphQL では、ニーズに合わせてデータを形作ることができるので、求めたものだけを受け取ることができます。

1. **抽象化**: GraphQL API には、言語にとらわれない標準を使用してデータを記述するいくつかのコンポーネントとシステムが含まれています。つまり、データの形状と構造が標準化されているので、フロントエンドとバックエンドの両方がネットワーク上でどのように送信されるかがわかります。これにより、開発者は両方とも GraphQL のシステムを操作でき、そのまわりに煩わされることはありません。

1. **迅速な反復**: データの標準化により、開発の一方の端での変更が他方の端では必要ない場合があります。例えば、GraphQL ではデータ仕様を簡単に変更できるため、フロントエンドのプレゼンテーションを変更しても、バックエンドに大きな変更が加えられない場合があります。アプリケーションの成長に合わせて、データの形状を定義または変更するだけで、アプリケーションのニーズに合わせることができます。その結果、潜在的な開発作業が少なくなります。

これらは、GraphQL の利点のほんの一部です。次のいくつかのセクションでは、GraphQL の構造と、GraphQL を REST のユニークな代替手段にするプロパティについて学びます。

# GraphQL API のコンポーネント
<a name="api-components"></a>

標準の GraphQL API は、クエリされるデータの形状を処理する単一のスキーマで構成されています。スキーマは、データベースや Lambda 関数などの 1 つ以上のデータソースにリンクされています。2 つのリゾルバーの間には、リクエストのビジネスロジックを処理する 1 つ以上のリゾルバーがあります。各コンポーネントは、GraphQL 実装において重要な役割を担います。以下のセクションでは、これら 3 つのコンポーネントと、それらが GraphQL サービスで果たす役割を紹介します。

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


**Topics**
+ [GraphQL スキーマ](schema-components.md)
+ [データソース](data-source-components.md)
+ [リゾルバー](resolver-components.md)

# GraphQL スキーマ
<a name="schema-components"></a>

GraphQL スキーマは GraphQL API の基盤です。データの形状を定義する設計図として機能します。また、データの取得方法や変更方法を定義する、クライアントとサーバー間の契約でもあります。

GraphQL スキーマは *スキーマ定義言語* (SDL) で記述されています。SDL は、構造が確立された型とフィールドで構成されています。
+ **タイプ**: タイプとは、GraphQL がデータの形状と動作を定義する方法です。GraphQL は、このセクションの後半で説明する多数の型をサポートしています。スキーマで定義されている各タイプには、独自のスコープが含まれます。スコープ内には、GraphQL サービスで使用される値またはロジックを含むことができる 1 つ以上のフィールドがあります。型にはさまざまな役割がありますが、最も一般的なのはオブジェクトまたはスカラー (プリミティブ値型) です。
+ **フィールド**: フィールドはタイプのスコープ内に存在し、GraphQL サービスから要求された値を保持します。これらは他のプログラミング言語の変数とよく似ています。フィールドで定義するデータの形状によって、リクエスト/レスポンス操作におけるデータの構造が決まります。これにより、開発者はサービスのバックエンドがどのように実装されているかを知らなくても、何が返されるかを予測できます。

スキーマがどのようなものかを視覚化するために、単純な GraphQL スキーマの内容を確認してみましょう。プロダクションコードでは、スキーマは通常、`schema.graphql` または `schema.json` というファイルにあります。GraphQL サービスを実装するプロジェクトを覗き見していると仮定しましょう。このプロジェクトには会社の人事データが保存されており、`schema.graphql` ファイルを使用して人事データを取得したり、データベースに新しい人員を追加したりしています。コードは次のようになります。

------
#### [ schema.graphql ]

```
type Person {                                  
   id: ID!
   name: String                                  
   age: Int
}
type Query {                                   
  people: [Person]
}
type Mutation {
  addPerson(id: ID!, name: String, age: Int): Person
}
```

------

スキーマには、`Person`、`Query`、`Mutation` の 3 つのタイプが定義されていることがわかります。`Person` を見てみると、これが会社の従業員のインスタンスの設計図であり、それによってこの型がオブジェクトになることが推測できます。そのスコープ内には、`id`、`name`、`age` があります。これらは `Person` のプロパティを定義するフィールドです。つまり、データソースはそれぞれの`Person`の`name`を`String`スカラー (プリミティブ) タイプとして、`age` をスカラー (プリミティブ) タイプとして格納します。`id` はそれぞれの `Person` に対して固有の特別な識別子として機能します。`!` 記号で示されているように、これは必須の値でもあります。

次の 2 つのオブジェクトタイプは動作が異なります。GraphQL は、スキーマへのデータの入力方法を定義する特別なオブジェクトタイプ用にいくつかのキーワードを予約しています。`Query` タイプはソースからデータを取得します。この例では、クエリはデータベースから `Person` オブジェクトを取得する場合があります。これは、RESTful 用語で使われる `GET` 操作を思い起こさせるかもしれません。`Mutation` はデータを変更します. この例では、ミューテーションによってデータベースにさらに `Person` オブジェクトが追加される可能性があります。これにより、`PUT` や `POST` のような状態を変更する操作を思い起こさせるかもしれません。特殊なオブジェクトタイプの動作については、このセクションの後半で説明します。

この例では、`Query` がデータベースから何かを取得すると仮定しましょう。`Query` のフィールドを見ると、`people` というフィールドが 1 つあります。フィールドの値は `[Person]` です。つまり、データベース内の `Person` の一部のインスタンスを取得したいということです。ただし、括弧を追加すると、特定のインスタンスだけでなく、すべての `Person` インスタンスのリストを返したいということになります。

データ変更などの状態を変更する操作は `Mutation` タイプが担当します。ミューテーションは、データソースに対して何らかの状態変更操作を実行する役割を果たします。この例では、データベースに新しい `addPerson` オブジェクトを追加する `Person` という操作がミューテーションに含まれています。このミューテーションは `Person` を使用し、`id`、`name`、`age` フィールドへの入力を期待しています。

この時点で、このような操作は何らかの動作を行い、関数名とパラメータを持つ関数によく似ているはずなのに、コード実装なしで `addPerson` がどのように動作するのか疑問に思われるかもしれません。現在のところ、スキーマは宣言の役割を果たすだけなので、機能しません。`addPerson` の動作を実装するには、リゾルバーを追加する必要があります。リゾルバーは、関連するフィールド (この場合は `addPerson` オペレーション) が呼び出されるたびに実行されるコードの単位です。オペレーションを使いたい場合は、どこかの時点でリゾルバーの実装を追加する必要があります。ある意味では、スキーマ操作は関数宣言、リゾルバーは定義と考えることができます。リゾルバーについては別のセクションで説明します。

この例は、スキーマがデータを操作する最も簡単な方法のみを示しています。GraphQL と AWS AppSyncの機能を活用して、複雑で堅牢でスケーラブルなアプリケーションを構築します。次のセクションでは、スキーマで使用できるさまざまなタイプとフィールドの動作をすべて定義します。

# GraphQL タイプ
<a name="graphql-types"></a>

GraphQL は、さまざまなタイプをサポートします。前のセクションで見たように、タイプはデータの形状や動作を定義します。これらは GraphQL スキーマの基本的な構成要素です。

タイプは入力と出力に分類できます。入力は特殊なオブジェクトタイプ (`Query`、`Mutation` など) の引数として渡すことができるタイプですが、出力タイプはデータの保存と返しにのみ使用されます。タイプとその分類のリストは以下のとおりです。
+ **オブジェクト**: オブジェクトにはエンティティを説明するフィールドが含まれます。例えば、`book`、`authorName`、`publishingYear` などの特性を記述するフィールドを持つオブジェクトのようなものが考えられます。これらは厳密には出力タイプです。
+ **スカラー**: これらは int や string などのプリミティブ型です。通常はフィールドに割り当てられます。`authorName` フィールドを例にとると、「John Smith」のような名前を格納する `String` スカラーを割り当てることができます。スカラーは入力タイプでも出力タイプでもかまいません。
+ **入力**: 入力では、フィールドグループを引数として渡すことができます。オブジェクトとよく似た構造ですが、特別なオブジェクトに引数として渡すことができます。入力を使うと、スカラー、列挙型、その他の入力をスコープ内で定義できます。入力は入力タイプにしかなりません。
+ **特殊オブジェクト**: 特殊オブジェクトは状態を変更する操作を実行し、サービスの面倒な作業の大部分を行います。特殊なオブジェクトタイプには、クエリ、ミューテーション、サブスクリプションの 3 種類があります。通常、クエリはデータを取得し、ミューテーションはデータを操作し、サブスクリプションはクライアントとサーバー間の双方向接続を開いて維持し、常時通信を行います。特殊オブジェクトは、その機能上、入力でも出力でもありません。
+ **列挙型**: 列挙型はあらかじめ定義された有効な値のリストです。列挙型を呼び出す場合、その値はそのスコープで定義されている値のみになります。例えば、交通信号のリストを表すという `trafficLights` がある場合、それには`redLight` や `greenLight` などの値が含まれることがありますが、`purpleLight` にはなり得ません。実際の信号機には信号の数が限られているため、列挙型を使用して信号を定義し、`trafficLight` 参照時にそれらだけが有効な値になるように強制できます。列挙型は入力型でも出力型でもかまいません。
+ **ユニオン/インターフェース**: ユニオンを使うと、クライアントからリクエストされたデータに応じて 1 つ以上のものをリクエストで返すことができます。例えば、`title` フィールドのある `Book` 型と `name` フィールドのある `Author` 型がある場合、両方の型を結合することができます。クライアントが「ジュリアス・シーザー」というフレーズをデータベースから検索したい場合、ユニオンは**ジュリアス・シーザー (ウィリアム・シェイクスピアの戯曲) を `Book` `title` から、**ジュリアス・シーザー(**『コメンタリー・デ・ベロ・ガリコ』の作者) を `Author` `name` から返すことができます。ユニオンは出力タイプとしてのみ使用できます。

  インターフェースは、オブジェクトが実装しなければならないフィールドのセットです。これは、Java などのプログラミング言語のインターフェースに少し似ていますが、インターフェースで定義されたフィールドを実装する必要があります。例えば、`Book``title`フィールドを含むというインターフェースを作成するとします。後で、`Book` を実装したもの `Novel` という型を作成したとします。`Novel` には `title` フィールドを含める必要があります。ただし、`Novel` には、`pageCount` または `ISBN` のような、インターフェイスにない他のフィールドも含めることができます。インターフェースは出力タイプにしかなれません。

以下のセクションでは、各タイプが GraphQL でどのように機能するかを説明します。

## オブジェクト
<a name="object-components"></a>

GraphQL オブジェクトは、プロダクションコードでよく使われるタイプです。GraphQL では、オブジェクトは異なるフィールドの集まりであり (他の言語の変数と同様)、各フィールドは値を保持できる型 (通常はスカラーまたは別のオブジェクト) によって定義されます。オブジェクトは、サービス実装から取得/操作できるデータの単位です。

オブジェクトタイプは `Type` キーワードを使用して宣言されます。スキーマの例を少し変更してみましょう。

```
type Person {
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}
```

ここでのオブジェクトタイプは `Person` と `Occupation` です。各オブジェクトには独自のフィールドと独自のタイプがあります。GraphQL の特徴の 1 つは、フィールドを他のタイプに設定できることです。`Person` の `occupation` フィールドには `Occupation` オブジェクトタイプが含まれていることがわかります。GraphQL はデータを記述するだけで、サービスの実装は記述していないため、この関連付けを行うことができます。

## スカラー
<a name="scalar-components"></a>

スカラーは基本的に、値を保持するプリミティブ型です。には AWS AppSync、デフォルトの GraphQL スカラーとスカラーという 2 AWS AppSync 種類のスカラーがあります。スカラーは通常、オブジェクトタイプ内のフィールド値を格納するために使用されます。GraphQL のデフォルトタイプには `Int`、`Float`、`String`、`Boolean`、`ID` が含まれます。前の例をもう一度使ってみましょう。

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}
```

`name` および `title` フィールドを除くと、どちらも `String` スカラーになります。`Name` は "`John Smith`" のような文字列値を返すことができ、タイトルは "`firefighter`" のようなものを返すことができます。一部の GraphQL 実装では、`Scalar` キーワードを使用してタイプの動作を実装するカスタムスカラーもサポートしています。ただし、 AWS AppSync は現時点ではカスタムスカラーを**サポートしていません**。スカラーのリストについては、「[AWS AppSyncのスカラータイプ](https://docs.aws.amazon.com//appsync/latest/devguide/scalars.html)」を参照してください。

## 入力
<a name="input-components"></a>

入力型と出力型の概念により、引数を渡すときには一定の制限があります。一般的に渡す必要がある型、特にオブジェクトには制限があります。入力タイプを使用すると、このルールを回避できます。入力は、スカラー、列挙型、その他の入力タイプを含むタイプです。

入力は `input` キーワードを使用して定義されます。

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}

input personInput { 
  id: ID!
  name: String
  age: Int
  occupation: occupationInput
}

input occupationInput {
  title: String
}
```

ご覧のとおり、元の型を模倣した入力を別々に設定できます。これらの入力は、次のようなフィールド操作でよく使用されます。

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}

input occupationInput {
  title: String
}

type Mutation {
  addPerson(id: ID!, name: String, age: Int, occupation: occupationInput): Person
}
```

まだ `Occupation` の代わりに `occupationInput` を渡して `Person` を作成することに注意してください。

これは入力の 1 つのシナリオに過ぎません。必ずしもオブジェクトを 1:1 でコピーする必要はありませんし、プロダクションコードでは、このような方法を使用することはほとんどありません。引数として入力する必要があるものだけを定義して、GraphQL スキーマを活用するとよいでしょう。

また、同じ入力を複数の操作で使用することもできますが、これはお勧めしません。スキーマの要件が変更された場合に備えて、各操作には入力の固有のコピーが含まれているのが理想的です。

## 特殊なオブジェクト
<a name="special-object-components"></a>

GraphQL は、スキーマがデータを取得/操作する方法に関するビジネスロジックの一部を定義する特別なオブジェクト用にいくつかのキーワードを予約しています。スキーマには、これらのキーワードがそれぞれ 1 つしか存在できません。これらは、クライアントが GraphQL サービスに対して実行するすべての要求されたデータのエントリポイントとして機能します。

特別なオブジェクトも `type` キーワードを使って定義されます。通常のオブジェクトタイプとは使い方が異なりますが、実装は非常に似ています。

------
#### [ Queries ]

クエリは、読み取り専用のフェッチを実行してソースからデータを取得するという点で `GET` オペレーションとよく似ています。GraphQL では、`Query` がサーバーに対してリクエストを行うクライアントのすべてのエントリポイントを定義します。GraphQL の実装には `Query` が必ずあります。

前のスキーマの例で使用した `Query` と変更されたオブジェクトタイプは次のとおりです。

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}
type Occupation {
  title: String
}
type Query {                                   
  people: [Person]
}
```

`Query` には、データソースか `Person` インスタンスのリストを返す `people` というフィールドがあります。アプリケーションの動作を変更する必要があり、今度は別の目的で `Occupation` インスタンスのみのリストを返す必要があるとしましょう。これをクエリに追加するだけで済みます。

```
type Query {                                   
  people: [Person]
  occupations: [Occupation]
}
```

GraphQL では、クエリをリクエストの単一ソースとして扱うことができます。お分かりのように、これは、異なるエンドポイントを使用して同じこと (`.../api/1/people` と `.../api/1/occupations`) を実現する RESTful な実装よりもずっと簡単になる可能性があります。

このクエリ用のリゾルバー実装があると仮定すると、実際のクエリを実行できるようになります。`Query` タイプは存在しますが、アプリケーションのコードで実行するには明示的に呼び出す必要があります。これは `query` キーワードを使用して行うことができます。

```
query getItems {
   people {
      name
   }
   occupations {
      title
   }
}
```

ご覧のとおり、このクエリは `getItems` と呼ばれ、`people` (`Person` オブジェクトのリスト) と`occupations` (`Occupation` オブジェクトのリスト) を返します。`people` では、それぞれの `Person` の `name` フィールドのみを返し、それぞれの `Occupation` の `title` フィールドを返しています。また、レスポンスは次のようになります。

```
{
  "data": {
    "people": [
      {
        "name": "John Smith"
      },
      {
        "name": "Andrew Miller"
      },
      .
      .
      .
    ],
    "occupations": [
      {
        "title": "Firefighter"
      },
      {
        "title": "Bookkeeper"
      },
      .
      .
      .
    ]
  }
}
```

レスポンス例は、データがクエリの形状に従っていることを示している。取得された各エントリは、フィールドの範囲内で一覧表示されます。`people` と `occupations`をそれぞれを個別のリストとして返しています。便利ですが、ユーザーの名前と職業のリストを返すようにクエリを変更したほうが便利かもしれません。

```
query getItems {
   people {
      name   
      occupation {
        title
      }
}
```

`Person` タイプには `Occupation` タイプの `occupation` フィールドが含まれているので、これは合法的な変更です。`people` の範囲内にリストされている場合は、`title` によって関連する `Occupation` とともにそれぞれの `Person` の `name` を返すことになります。また、レスポンスは次のようになります。

```
}
  "data": {
    "people": [
      {
        "name": "John Smith",
        "occupation": {
          "title": "Firefighter"
        }
      },
      {
        "name": "Andrew Miller",
        "occupation": {
          "title": "Bookkeeper"
        }
      },
      .
      .
      .
    ]
  }
}
```

------
#### [ Mutations ]

ミューテーションは、`PUT` や `POST` のような状態を変える操作に似ています。書き込み操作を実行してソース内のデータを変更し、レスポンスを取得します。データ変更リクエストのエントリポイントを定義します。クエリとは異なり、ミューテーションはプロジェクトのニーズに応じてスキーマに含まれる場合と含まれない場合があります。スキーマの例からのミューテーションは次のとおりです。

```
type Mutation {
  addPerson(id: ID!, name: String, age: Int): Person
}
```

`addPerson` フィールドは、`Person` をデータソースに追加する 1 つのエントリポイントを表します。`addPerson` はフィールド名、`id`、`name`、`age` はパラメータ、`Person` は戻り型です。`Person` タイプを振り返ってみます。

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}
```

`occupation` フィールドを追加しました。ただし、オブジェクトは引数として渡すことができないため、このフィールドを直接 `Occupation` に設定することはできません。オブジェクトは厳密には出力タイプです。代わりに、同じフィールドを含む入力を引数として渡す必要があります。

```
input occupationInput {
  title: String
}
```

 新しいインスタンスを作るときに、パラメータとして含めるように簡単に `addPerson` を更新することもできます。

```
type Mutation {
  addPerson(id: ID!, name: String, age: Int, occupation: occupationInput): Person
}
```

更新されたスキーマは次のとおりです。

```
type Person { 
  id: ID!
  name: String
  age: Int
  occupation: Occupation
}

type Occupation {
  title: String
}

input occupationInput {
  title: String
}

type Mutation {
  addPerson(id: ID!, name: String, age: Int, occupation: occupationInput): Person
}
```

元のオブジェクトの代わりに、`occupation` が `occupationInput` から `title` フィールドに渡すことで `Person` の作成が完了することに注意してください。`addPerson` のリゾルバーの実装があると仮定すると、実際のミューテーションを実行できるようになりました。`Mutation` 型は存在しますが、アプリケーションのコードで実行するには明示的に呼び出す必要があります。これは `mutation` キーワードを使用して行うことができます。

```
mutation createPerson {
  addPerson(id: ID!, name: String, age: Int, occupation: occupationInput) {
    name
    age
    occupation {
      title
    }
  }
}
```

このミューテーションは `createPerson` と呼ばれ、`addPerson` がオペレーションです。新しい `Person` を作成するには `id`、`name`、`age`、`occupation` の引数を入力します。`addPerson` の範囲には、`name`、`age` などの他のフィールドもあります。これはあなたのレスポンスです。これらは `addPerson` オペレーションが完了した後に返されるフィールドです。この例の最後の部分は次のとおりです。

```
mutation createPerson {
  addPerson(id: "1", name: "Steve Powers", age: "50", occupation: "Miner") {
    id
    name
    age
    occupation {
      title
    }
  }
}
```

このミューテーションを使用すると、結果は以下のようになります。

```
{
  "data": {
    "addPerson": {
      "id": "1",
      "name": "Steve Powers",
      "age": "50",
      "occupation": {
        "title": "Miner"
      }
    }
  }
}
```

ご覧のとおり、レスポンスはリクエストした値を、ミューテーションで定義したのと同じ形式で返しました。混乱を減らし、今後さらにクエリが必要にならないように、変更されたすべての値を返すことをお勧めします。ミューテーションを使うと、複数の操作をその範囲に含めることができます。これらはミューテーションにリストされている順序で順番に実行されます。例えば、データソースに役職を追加する `addOccupation` という操作をもう 1 つ作成した場合、これを `addPerson` の後にミューテーションで呼び出すことができます。`addPerson` が最初に処理され、その後に `addOccupation` が処理されます。

------
#### [ Subscriptions ]

サブスクリプションは [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_client_applications) を使用して、サーバーとクライアント間の永続的な双方向接続を開きます。通常、クライアントはサーバーをサブスクライブまたはリッスンします。サーバーがサーバー側で変更を加えたり、イベントを実行したりするたびに、サブスクライブしているクライアントは更新を受け取ります。このタイプのプロトコルは、複数のクライアントがサブスクライブしていて、サーバーや他のクライアントで発生した変更について通知を受ける必要がある場合に役立ちます。例えば、サブスクリプションを使用してソーシャルメディアフィードを更新できます。ユーザー A とユーザー B の 2 人のユーザーが、どちらもダイレクトメッセージを受信するたびに自動通知更新をサブスクライブしている場合があります。クライアント A のユーザー A は、クライアント B のユーザー B にダイレクトメッセージを送信できます。ユーザー A のクライアントはダイレクトメッセージを送信し、サーバーによって処理されます。その後、サーバーはユーザー B のアカウントにダイレクトメッセージを送信し、クライアント B には自動通知を送信します。

スキーマの例に追加できる `Subscription` の例を以下に示します。

```
type Subscription {                                   
  personAdded: Person
}
```

`personAdded` フィールドは、データソースに新しい `Person` が追加されるたびに、サブスクライブしているクライアントにメッセージを送信します。`personAdded` のリゾルバーの実装があると仮定すると、サブスクリプションを使用できるようになりました。`Subscription` 型は存在しますが、アプリケーションのコード内で実行するには明示的に呼び出す必要があります。これは `subscription` キーワードを使用して行うことができます。

```
subscription personAddedOperation {
  personAdded {
    id
    name
  }
}
```

サブスクリプションは `personAddedOperation` と呼ばれ、オペレーションは `personAdded` です。`personAdded` は新しい `Person` インスタンスの `id` および `name` フィールドを返します。ミューテーションの例を見てみると、以下の操作を使用して `Person` を追加しました。

```
addPerson(id: "1", name: "Steve Powers", age: "50", occupation: "Miner")
```

クライアントが新しく追加された `Person` へのアップデートを購読していた場合、`addPerson` 実行後に以下のように表示されるかもしれません。

```
{
  "data": {
    "personAdded": {
      "id": "1",
      "name": "Steve Powers"
    }
  }
}
```

以下は、サブスクリプションが提供するものの概要です。

サブスクリプションは、クライアントとサーバーが迅速で安定したアップデートを受信できるようにする双方向のチャネルです。通常、標準化された安全な接続を実現する WebSocket プロトコルを使用します。

サブスクリプションは、接続設定のオーバーヘッドを減らすという点で機敏です。一度サブスクライブすると、クライアントはそのサブスクリプションで長期間稼働し続けることができます。通常、開発者がサブスクリプションの有効期間を調整したり、要求される情報を設定したりできるようにすることで、コンピューティングリソースを効率的に使用します。

一般に、サブスクリプションを使用すると、クライアントは一度に複数のサブスクリプションを作成できます。サブスクリプションは AWS AppSync、 AWS AppSync サービスからのリアルタイム更新の受信にのみ使用されます。クエリやミューテーションの実行には使用できません。

サブスクリプションに代わる主な方法はポーリングです。ポーリングでは、設定した間隔でクエリを送信してデータを要求します。このプロセスは通常、サブスクリプションほど効率的ではなく、クライアントとバックエンドの両方に大きな負担をかけます。

------

スキーマの例では言及されていなかったことの 1 つは、特殊なオブジェクト型も `schema` ルートで定義しなければならないという事実です。したがって、スキーマをエクスポートすると AWS AppSync、次のようになります。

------
#### [ schema.graphql ]

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

.
.
.

type Query {                                   
  # code goes here
}
type Mutation {                                   
  # code goes here
}
type Subscription {                                   
  # code goes here
}
```

------

## 列挙型
<a name="enum-components"></a>

列挙型は、タイプやフィールドが持つ可能性のある有効な引数を制限する特殊なスカラーです。つまり、スキーマで列挙型が定義されると、それに関連するタイプまたはフィールドは列挙型内の値に限定されます。列挙型は文字列スカラーとしてシリアル化されます。プログラミング言語が異なれば、GraphQL 列挙型の処理も異なる場合があることに注意してください。例えば、JavaScript はネイティブの列挙型をサポートしていないため、代わりに列挙値を int 値にマップできます。

列挙型は `enum` キーワードを使用して定義されます。例を示します。

```
enum trafficSignals {
  solidRed
  solidYellow
  solidGreen
  greenArrowLeft
  ...
}
```

`trafficLights` 列挙型を呼び出すとき、引数に指定できるのは `solidRed`、`solidYellow`、`solidGreen` などのみです。列挙型を使うのは、はっきりしているが選択肢の数が限られているものを表すのに使うのが一般的です。

## ユニオン/インターフェース
<a name="union-interface-components"></a>

GraphQL の「[Interface と Union](https://docs.aws.amazon.com/appsync/latest/devguide/interfaces-and-unions.html)」を参照してください。

# GraphQL フィールド
<a name="graphql-fields"></a>

フィールドはタイプのスコープ内に存在し、GraphQL サービスから要求された値を保持します。これらは、他のプログラミング言語の変数とよく似ています。例えば、次のような `Person` オブジェクトタイプがあります。

```
type Person {                                  
   name: String                                  
   age: Int
}
```

この場合のフィールドはそれぞれ `name` `age` で、`String` および `Int` 値が格納されます。上に示したようなオブジェクトフィールドは、クエリやミューテーションのフィールド (オペレーション) の入力として使用できます。例については、以下の `Query` を参照してください

```
type Query {                                   
  people: [Person]
}
```

`people` フィールドは、データソースから `Person` のすべてのインスタンスを要求しています。GraphQL サーバーで `Person` を追加または取得すると、データはタイプとフィールドの形式に従うことが期待できます。つまり、スキーマ内のデータの構造によって、レスポンスでどのように構造化されるかが決まります。

```
}
  "data": {
    "people": [
      {
        "name": "John Smith",
        "age": "50"
      },
      {
        "name": "Andrew Miller",
        "age": "60"
      },
      .
      .
      .
    ]
  }
}
```

フィールドはデータを構造化する上で重要な役割を果たします。以下で説明するように、フィールドに適用してさらにカスタマイズできるプロパティがいくつかあります。

## Lists
<a name="list-components"></a>

リストは指定されたタイプのすべての項目を返します。リストは括弧 `[]` を使ってフィールドの型に追加できます。

```
type Person { 
  name: String
  age: Int
}
type Query {                                   
  people: [Person]
}
```

`Query` では、`Person` を囲んでいる括弧は、データソースからの `Person` のすべてのインスタンスを配列として返したいことを示しています。レスポンスでは、それぞれの `Person`の `name` および `age` の値が 1 つの区切りリストとして返されます。

```
}
  "data": {
    "people": [
      {
        "name": "John Smith",         # Data of Person 1
        "age": "50"
      },
      {
        "name": "Andrew Miller",      # Data of Person 2
        "age": "60"
      },
      .                               # Data of Person N
      .
      .
    ]
  }
}
```

使用できるのは特殊なオブジェクトタイプだけではありません。リストは通常のオブジェクトタイプのフィールドでも使用できます。

## NULL 以外
<a name="non-null-components"></a>

NULL 以外は、レスポンスで NULL であってはならないフィールドを示します。`!` 記号を使用して、フィールドを NULL 以外に設定できます。

```
type Person { 
  name: String!
  age: Int
}
type Query {                                   
  people: [Person]
}
```

`name` フィールドを明示的に NULL にすることはできません。データソースにクエリを実行して、このフィールドに NULL を入力すると、エラーが発生します。

リストと NULL 以外を組み合わせることができます。次のクエリを比較してください。

```
type Query {                                   
  people: [Person!]      # Use case 1
}

.
.
.

type Query {                                   
  people: [Person]!      # Use case 2
}

.
.
.

type Query {                                   
  people: [Person!]!     # Use case 3
}
```

ユースケース 1 では、リストに NULL 項目を含めることはできません。ユースケース 2 では、リスト自体を NULL に設定することはできません。ユースケース 3 では、リストとその項目を NULL にすることはできません。ただし、いずれにしても、空のリストを返すことはできます。

ご覧のとおり、GraphQL には動くコンポーネントがたくさんあります。このセクションでは、単純なスキーマの構造と、スキーマがサポートするさまざまなタイプとフィールドを示しました。次のセクションでは、GraphQL API の他のコンポーネントと、それらがスキーマとどのように連携するかを説明します。

# データソース
<a name="data-source-components"></a>

前のセクションでは、スキーマがデータの形状を定義することを学びました。ただし、そのデータがどこから来たのかについては説明していません。実際のプロジェクトでは、スキーマはサーバーへのすべてのリクエストを処理するゲートウェイのようなものです。リクエストが行われると、スキーマはクライアントと接続する単一のエンドポイントとして機能します。スキーマはデータソースのデータにアクセスして処理し、クライアントに中継します。以下のインフォグラフィックを参照してください。

![\[GraphQL schema integrating multiple AWS のサービス for a single endpoint API architecture.\]](http://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/images/aws-flow-infographic.png)


AWS AppSync と GraphQL は、バックエンドのフロントエンド (BFF) ソリューションを完全に実装します。これらは連携して、バックエンドを抽象化することで大規模な複雑さを軽減します。サービスで異なるデータソースやマイクロサービスを使用している場合は、各ソース (サブグラフ) のデータの形状を単一のスキーマ (スーパーグラフ) で定義することで、複雑さをある程度抽象化できます。つまり、GraphQL API は 1 つのデータソースの使用に限定されないということです。GraphQL API には任意の数のデータソースを関連付けて、それらがサービスとどのように相互作用するかをコードで指定できます。

インフォグラフィックでわかるように、GraphQL スキーマには、クライアントがデータを要求するために必要なすべての情報が含まれています。つまり、REST のように複数のリクエストを処理するのではなく、1 つのリクエストですべてを処理できるということです。これらのリクエストは、サービスの唯一のエンドポイントであるスキーマを通過します。リクエストが処理されると、リゾルバー (次のセクションで説明) がコードを実行して、関連するデータソースからのデータを処理します。レスポンスが返されると、データソースに関連付けられているサブグラフにスキーマ内のデータが入力されます。

AWS AppSync は、さまざまなデータソースタイプをサポートしています。以下の表では、各タイプについて説明し、それぞれの利点を列挙し、さらに詳しい情報を得るために役立つリンクを示します。


| データソース | 説明 | 利点 | 補足情報 | 
| --- | --- | --- | --- | 
| Amazon DynamoDB | Amazon DynamoDB は、フルマネージド NoSQL データベースサービスであり、シームレスなスケーラビリティを備えた高速で予測可能なパフォーマンスを提供します。DynamoDB を使用すると、ディストリビューションデータベースの運用とスケーリングに伴う管理作業をまかせることができるため、ハードウェアのプロビジョニング、設定と構成、レプリケーション、ソフトウェアパッチ適用、クラスタースケーリングなどを自分で行う必要はなくなります。また、DynamoDB も保管時の暗号化を提供し、機密データの保護における負担と複雑な作業を解消します。 |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/data-source-components.html)  | 
| AWS Lambda | AWS Lambda は、サーバーのプロビジョニングや管理を行わずにコードを実行できるようにするコンピューティングサービスです。Lambda は可用性の高いコンピューティングインフラストラクチャでコードを実行し、コンピューティングリソースに関するすべての管理を行います。これには、サーバーおよびオペレーティングシステムのメンテナンス、容量のプロビジョニングおよび自動スケーリング、さらにログ記録などが含まれます。Lambda で必要なことは、サポートするいずれかの言語ランタイムにコードを与えることだけです。」 |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/data-source-components.html)  | 
| OpenSearch | 「Amazon OpenSearch Service は、 AWS クラウドでの OpenSearch クラスターのデプロイ、運用、スケーリングを容易にするマネージドサービスです。Amazon OpenSearch Service は、OpenSearch および従来の Elasticsearch OSS (ソフトウェアのファイナルオープンソースバージョンである 7.10 まで) をサポートしています。クラスターを作成するときに、どの検索エンジンを使用するかのオプションがあります。**OpenSearch** はログ分析、リアルタイムのアプリケーションモニタリング、クリックストリーム分析などのユースケース向けの、完全なオープンソースの検索および分析エンジンです。詳細については、「[OpenSearch ドキュメント](https://opensearch.org/docs/)」を参照してください。**Amazon OpenSearch Service** は、OpenSearch クラスターのすべてのリソースをプロビジョニングして、OpenSearch クラスターを起動します。また、障害が発生した OpenSearch Service ノードを自動的に検出して置き換え、セルフマネージドインフラストラクチャに関連するオーバーヘッドを減らします。また、単一の API コールを使用するか、コンソールで数回クリックするだけで、クラスターを簡単にスケーリングできます。 |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/data-source-components.html)  | 
| HTTP エンドポイント | HTTP エンドポイントをデータソースとして使用できます。 AWS AppSync は、パラメータやペイロードなどの関連情報を含むリクエストをエンドポイントに送信できます。HTTP レスポンスはリゾルバーに公開され、リゾルバーは操作終了後に最終レスポンスを返します。 |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/data-source-components.html)  | 
| Amazon EventBridge | EventBridge は、イベントを使用してアプリケーションコンポーネント同士を接続するサーバーレスサービスです。これにより、スケーラブルなイベント駆動型アプリケーションを簡単に構築できます。これを使用して、自社開発のアプリケーション、 AWS サービス、サードパーティーソフトウェアなどのソースから組織全体のコンシューマーアプリケーションにイベントをルーティングします。EventBridge では、イベントの取り込み、フィルタリング、変換、配信をシンプルかつ一貫性のある方法で行うことができるため、新しいアプリケーションをすばやく構築できます。 |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/data-source-components.html)  | 
| リレーショナルデータベース | Amazon Relational Database Service (Amazon RDS)」は、 AWS クラウドでのリレーショナルデータベースのセットアップ、運用、スケーリングを容易にするウェブサービスです。業界スタンダードのリレーショナルデータベース向けに、費用対効果に優れたエクステンションを備え、一般的なデータベース管理タスクを管理します。」 |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/data-source-components.html)  | 
| none データソース | データソースサービスを使用する予定がない場合は、none に設定できます。none データソースは、設定後も明示的にデータソースとして分類されますが、ストレージメディアではありません。とはいえ、データ操作やパススルーには依然として役立つ場合があります。 |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/data-source-components.html)  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/data-source-components.html)  | 

**ヒント**  
データソースとやり取りする方法の詳細については AWS AppSync、[「データソースのアタッチ](https://docs.aws.amazon.com//appsync/latest/devguide/attaching-a-data-source.html)」を参照してください。

# リゾルバー
<a name="resolver-components"></a>

前のセクションでは、スキーマとデータソースのコンポーネントについて学びました。次に、スキーマとデータソースがどのように相互作用するかを説明する必要があります。すべてはリゾルバーから始まります。

リゾルバーは、サービスにリクエストが送信されたときに、そのフィールドのデータをどのように解決するかを処理するコード単位です。リゾルバーは、スキーマのタイプ内の特定のフィールドにアタッチされます。クエリ、ミューテーション、サブスクリプションフィールド操作の状態変更操作を実装するために最もよく使用されます。リゾルバーはクライアントのリクエストを処理し、結果を返します。結果はオブジェクトやスカラーのような出力タイプのグループでもかまいません。

![\[GraphQL schema with resolvers connecting to various AWS data sources for a single endpoint.\]](http://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/images/aws-flow-infographic.png)


## リゾルバーランタイム
<a name="resolver-components-runtime"></a>

では AWS AppSync、まずリゾルバーのランタイムを指定する必要があります。リゾルバーランタイムは、リゾルバーが実行される環境を示します。また、リゾルバーが書き込まれる言語も指定します。 AWS AppSync 現在、 は APPSYNC\$1JS for JavaScript and Velocity Template Language (VTL) をサポートしています。JavaScript については「[リゾルバーおよび関数の JavaScript runtime 機能](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference-js.html)」または VTL については「[リゾルバーのマッピングテンプレートユーティリティーリファレンス](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-util-reference.html)」を参照してください。

## リゾルバーの構造
<a name="resolver-components-structure"></a>

コード的には、リゾルバーはいくつかの方法で構造化できます。**ユニット** リゾルバーと **パイプライン** リゾルバーがあります。

### ユニットリゾルバー
<a name="resolver-components-unit"></a>

ユニットリゾルバーは、データソースに対して実行される単一のリクエストハンドラーとレスポンスハンドラーを定義するコードで構成されています。リクエストハンドラーはコンテキストオブジェクトを引数として受け取り、データソースの呼び出しに使用されたリクエストペイロードを返します。レスポンスハンドラーは、実行されたリクエストの結果を含むペイロードをデータソースから受け取ります。レスポンスハンドラーは、ペイロードを GraphQL レスポンスに変換して GraphQL フィールドを解決します。

![\[GraphQL request flow showing request and response handlers interacting with a data source.\]](http://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/images/unit-resolver-js.png)


### パイプラインリゾルバー
<a name="resolver-components-pipeline"></a>

パイプラインリゾルバーを実装する場合、以下のような一般的な構造があります。
+ **before step**: クライアントからリクエストが送信されると、使用されているスキーマフィールド (通常はクエリ、ミューテーション、サブスクリプション) のリゾルバーにリクエストデータが渡されます。リゾルバーは before step ハンドラーを使用してリクエストデータの処理を開始します。これにより、データがリゾルバーを通過する前に一部の前処理操作を実行できます。
+ **関数**: before ステップが実行されると、リクエストは関数リストに渡されます。リストの最初の関数がデータソースに対して実行されます。関数は、独自のリクエストハンドラーとレスポンスハンドラーを含むリゾルバーのコードのサブセットです。リクエストハンドラーは、リクエストデータを取得し、データソースに対して操作を実行します。レスポンスハンドラーは、データソースのレスポンスを処理してからリストに戻します。関数が複数ある場合、リクエストデータはリスト内の次に実行される関数に送信されます。リスト内の関数は、開発者が定義した順序で連続して実行されます。すべての関数が実行されると、最終結果は後のステップに渡されます。
+ **after step**: after step は、GraphQL レスポンスに渡す前に、最終関数のレスポンスに対していくつかの最終オペレーションを実行できるハンドラー関数です。

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


## リゾルバーハンドラーの構造
<a name="resolver-components-handlers"></a>

ハンドラーは通常、`Request` および `Response` と呼ばれる関数です。

```
export function request(ctx) {
    // Code goes here
}

export function response(ctx) {
    // Code goes here
}
```

ユニットリゾルバーには、これらの関数のセットは 1 つしかありません。パイプラインリゾルバーには、処理前と処理後のステップ用にこれらのセットが 1 つあり、関数ごとに追加のセットがあります。これがどのようになるかを視覚化するために、単純な `Query` タイプを見てみましょう。

```
type Query {
	helloWorld: String!
}
```

これは `String` タイプの `helloWorld` というフィールドが 1 つある単純なクエリです。このフィールドには常に「Hello World」という文字列を返したいと仮定しましょう。この動作を実装するには、このフィールドにリゾルバーを追加する必要があります。ユニットリゾルバーには、次のようなものを追加できます。

```
export function request(ctx) {
    return {}
}

export function response(ctx) {
    return "Hello World"
}
```

データをリクエストしたり処理したりしていないので、`request` は空欄のままでも構いません。データソースは `None` だと仮定することもできます。つまり、このコードでは呼び出しを実行する必要がないということです。レスポンスは単に「Hello World」を返します。このリゾルバーをテストするには、次のクエリータイプを使用してリクエストを行う必要があります。

```
query helloWorldTest {
  helloWorld
}
```

これは `helloWorld` フィールドを返す `helloWorldTest` というクエリです。実行すると、`helloWorld` フィールドリゾルバーも実行され、レスポンスが返されます。

```
{
  "data": {
    "helloWorld": "Hello World"
  }
}
```

このような定数を返すのは一番簡単なことです。実際には、入力やリストなどを返すことになります。より複雑な例を次に示します。

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

type Query {
  getBooks: [Book]
}
```

ここでは、`Books` のリストを返しています。本のデータの保存に DynamoDB テーブルを使用していると仮定しましょう。ハンドラーは以下のようになります。

```
/**
 * Performs a scan on the dynamodb data source
 */
export function request(ctx) {
  return { operation: 'Scan' };
}

/**
 * return a list of scanned post items
 */
export function response(ctx) {
  return ctx.result.items;
}
```

このリクエストでは、組み込みのスキャン操作を使用してテーブル内のすべてのエントリを検索し、結果をコンテキストに保存して、レスポンスに渡しました。レスポンスは結果項目を受け取り、レスポンスとして返しました。

```
{
  "data": {
    "getBooks": {
      "items": [
        {
          "id": "abcdefgh-1234-1234-1234-abcdefghijkl",
          "title": "book1"
        },
        {
          "id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
          "title": "book2"
        },

        ...

      ]
    }
  }
}
```

## リゾルバーのコンテキスト
<a name="resolver-components-context"></a>

リゾルバーでは、ハンドラーチェーンの各ステップが前のステップのデータの状態を認識している必要があります。あるハンドラーの結果を保存して、引数として別のハンドラーに渡すことができます。GraphQL は 4 つの基本的なリゾルバー引数を定義しています。


****  

| リゾルバーベース引数 | 説明 | 
| --- | --- | 
| obj root、parent、など | 親の結果です。 | 
| args | GraphQL クエリのフィールドに提供される引数。 | 
| context | すべてのリゾルバーに提供される値で、現在ログインしているユーザーやデータベースへのアクセスなどの重要なコンテキスト情報を保持します。 | 
| info | スキーマの詳細だけでなく、現在のクエリに関連するフィールド固有の情報を保持する値です。 | 

では AWS AppSync、 `[context](https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html)` (ctx) 引数は上記のすべてのデータを保持できます。これはリクエストごとに作成されるオブジェクトで、認可情報、結果データ、エラー、リクエストメタデータなどのデータを含みます。コンテキストを使うと、プログラマーはリクエストの他の部分からのデータを簡単に操作できます。このスニペットをもう一度見てみましょう。

```
/**
 * Performs a scan on the dynamodb data source
 */
export function request(ctx) {
  return { operation: 'Scan' };
}

/**
 * return a list of scanned post items
 */
export function response(ctx) {
  return ctx.result.items;
}
```

リクエストにはコンテキスト (ctx) が引数として渡されます。これがリクエストの状態です。テーブル内のすべての項目をスキャンし、その結果を `result`のコンテキスト内の結果を格納します。次に、コンテキストが応答引数に渡され、応答引数が `result` にアクセスしてその内容を返します。

## リクエストとパーシング
<a name="resolver-ast"></a>

GraphQL サービスにクエリを行う場合、実行前に解析と検証のプロセスを実行する必要があります。リクエストは解析され、抽象構文ツリーに変換されます。ツリーの内容は、スキーマに対して複数の検証アルゴリズムを実行することによって検証されます。検証ステップの後、ツリーのノードがトラバースされ、処理されます。リゾルバーが呼び出され、結果がコンテキストに保存され、レスポンスが返されます。例えば、次のクエリを指定するとします。

```
query {
  Person {  //object type
    name  //scalar
    age   //scalar
  } 
}
```

戻り値は `name` および `age` フィールドとともに `Person` を返します。このクエリを実行すると、ツリーは次のようになります。

![\[Hierarchical diagram showing query, Person, name, and age nodes connected by arrows.\]](http://docs.aws.amazon.com/ja_jp/appsync/latest/devguide/images/ast-1.png)


ツリーから見ると、このリクエストはスキーマ内の `Query` をルートで検索しているようです。クエリの内部では、`Person` フィールドが解決されます。前の例から、これはユーザーからの入力であったり、値のリストなどが、必要なフィールド (`name` と `age`) を保持するオブジェクトタイプに関連付けられている可能性が高いことがわかっています。`Person`この 2 つの子フィールドが見つかると、指定された順序 (`name` の後に `age` が続く) で解決されます。ツリーが完全に解決されると、リクエストは完了し、クライアントに返送されます。

# GraphQL の追加プロパティ
<a name="graphql-properties"></a>

GraphQL は、規模を問わずシンプルさと堅牢性を維持するためのいくつかの設計原則で構成されています。

## 宣言型
<a name="declarative-property"></a>

GraphQL は宣言型です。つまり、ユーザーはクエリしたいフィールドを宣言するだけでデータを記述 (整形) できます。レスポンスはこれらのプロパティのデータのみを返します。例えば、ISBN 13 `id` の値が *9780199536061* の DynamoDB テーブル内の `Book` オブジェクトを取得するオペレーションを次に示します。

```
{
  getBook(id: "9780199536061") {
    name
    year
    author
  }
}
```

このレスポンスでは、ペイロード内のフィールド (`name`、`year`、`author`) が返され、それ以外は何も返されません。

```
{
  "data": {
    "getBook": {
      "name": "Anna Karenina",
      "year": "1878",
      "author": "Leo Tolstoy",
    }
  }
}
```

この設計原則により、GraphQL は、複雑なシステムで REST API が処理するオーバーフェッチとアンダーフェッチという根強い問題を排除します。その結果、データ収集がより効率的になり、ネットワークパフォーマンスが向上します。

## 階層的
<a name="hierarchical-property"></a>

GraphQL は、要求されたデータをアプリケーションのニーズに合わせてユーザーが形作ることができるという点で柔軟です。リクエストされたデータは、常に GraphQL API で定義されたプロパティのタイプと構文に従います。例えば、次のスニペットは、`Book` *9780199536061* にリンクされているすべての保存済み引用文字列とページを返す `quotes` という新しいフィールドスコープを使った `getBook` オペレーションを示しています。

```
{
  getBook(id: "9780199536061") {
    name
    year
    author
    quotes {
      description
      page
    }
  }
}
```

このクエリを実行すると次の結果を返します。

```
{
  "data": {
    "getBook": {
      "name": "Anna Karenina",
      "year": "1878",
      "author": "Leo Tolstoy",
      "quotes": [
         {
            "description": "The highest Petersburg society is essentially one: in it everyone knows everyone else, everyone even visits everyone else.",
            "page": 135
         },
         { 
            "description": "Happy families are all alike; every unhappy family is unhappy in its own way.",
            "page": 1
         },
         {        
            "description": "To Konstantin, the peasant was simply the chief partner in their common labor.",
            "page": 251
         }
      ]
    }
  }
}
```

ご覧のように、リクエストされた本にリンクされている `quotes` フィールドは、クエリで記述されたのと同じ形式の配列として返されました。ここでは示していませんが、GraphQL には、取得するデータの場所にこだわらないという利点もあります。`Books` と `quotes` は別々に保存することもできますが、アソシエーションが存在する限り、GraphQL は引き続き情報を取得します。つまり、クエリは 1 回のリクエストで多数のスタンドアロンデータを取得できるということです。

## イントロスペクティブ
<a name="introspective-property"></a>

GraphQL は自己文書化されている、つまりイントロスペクティブです。スキーマ内の基になる型やフィールドをユーザーが確認できるようにするいくつかの組み込み操作をサポートしています。例えば、`Foo` および`date` フィールドのある `description` 型があります。

```
type Foo {
	date: String
	description: String
}
```

`_type` オペレーションを使うと、スキーマの下にあるタイピングメタデータを検索できます。

```
{
  __type(name: "Foo") {
    name                   # returns the name of the type
    fields {               # returns all fields in the type
      name                 # returns the name of each field
      type {               # returns all types for each field
        name               # returns the scalar type
      }
    }
  }
}
```

これは応答を返します。

```
{
  "__type": {
    "name": "Foo",                     # The type name
    "fields": [
      {
        "name": "date",                # The date field
        "type": { "name": "String" }   # The date's type
      },
      {
        "name": "description",         # The description field
        "type": { "name": "String" }   # The description's type
      },
    ]
  }
}
```

この機能は、特定の GraphQL スキーマがどのタイプとフィールドをサポートしているかを調べるために使用できます。GraphQL は、さまざまなイントロスペクティブなオペレーションをサポートしています。詳細については、「[イントロスペクション](https://graphql.org/learn/introspection/)」を参照してください。

## 強力なタイピング
<a name="strong-typing-property"></a>

GraphQL は、型と項目のシステムを通じて厳密な型指定をサポートしています。スキーマで何かを定義する場合は、実行前に検証できる型でなければなりません。また、GraphQL の構文仕様に従わなければなりません。この概念は他の言語のプログラミングと何ら変わりはありません。例えば、先ほどの、`Foo` 型があります。

```
type Foo {
	date: String
	description: String
}
```

`Foo` が作成されるオブジェクトであることがわかります。`Foo` のインスタンス内には、`date` および `description` フィールドがあり、両方とも `String`プリミティブ型 (スカラー) です。構文的には、`Foo` が宣言されていて、そのフィールドがスコープ内に存在していることがわかります。このように型の確認と論理構文を組み合わせることで、GraphQL API は簡潔でわかりやすいものになります。GraphQL のタイピングと構文の仕様については、[こちら](https://spec.graphql.org/)を参照してください。