5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

今更AWS AppSync GraphQLに入門する

5
Last updated at Posted at 2026-04-20

はじめに

最近、Amplify Gen2を使ってWebアプリケーションの構築・デプロイを行うことが多くなりました。Claude Code様様です。Amplify Gen2ではバックエンドリソースも構築できるのですが、テンプレートを見ると、authとdataというディレクトリが存在します。authはAmazon Cognitoを定義するもので、dataはAppSync GraphQL + Amazon DynamoDBを定義するものです。「そういえばAppSyncってなんだ?」となったので試しながら調べてみました。

GraphQLとは

AppSyncの話の前に、まずはGraphQLについて整理します。

GraphQLは、GraphQLという仕様に基づいたAPIのクエリ言語で、必要な情報のみ取得できる特徴があります。

オーバーフェッチング

比較として、REST APIの例を出します。REST APIでは、エンドポイントごとにレスポンスの形が固定されています。例えば GET /users/{id} というエンドポイントがあるとして、呼び出すと次のようなレスポンスが返ってくるとします。

{
  "id": "001",
  "name": "あるけみー",
  "email": "alchemy@example.com",
  "address": "○○県...",
  "phone": "0A0-XXXX-XXXX",
  "createdAt": "2026-04-01T00:00:00Z"
}

もし画面でユーザー名だけ表示したい場合でも、name 以外の不要なフィールドも全部返ってきます。これをオーバーフェッチングと呼びます。

不要なデータを毎回転送し続けるため、ネットワーク帯域幅が無駄に消費されます。トラフィックが少ない場合にはさほど影響はないですが、大量のトラフィックが発生するWebシステムにおいて、使用しない情報を取得することで通信量が多くなりパフォーマンスに影響する可能性があります。

アンダーフェッチング

逆に、1つのエンドポイントで必要なデータが全部揃わず、複数回リクエストが必要になることもあります。例えば「ユーザー情報とそのユーザーの注文履歴を一緒に取得したい」という場合、GET /users/{id}GET /orders?userId={id} の2回リクエストしなければなりません。これをアンダーフェッチングと呼びます。リクエスト回数が増えることでパフォーマンスに影響が出る可能性があります。

GraphQLによる解決

GraphQLはこれらの問題を解決するために設計されており、クライアント側が必要なフィールドだけ指定できることが最大の特徴です。1つのエンドポイントに対して必要なデータ構造を記述してリクエストします。

query {
  getUser(id: "001") {
    name
  }
}

このクエリを送れば name だけが返ってきます。関連データをまとめて取得することも可能です。

query {
  getUser(id: "001") {
    name
    orders {
      id
      amount
    }
  }
}

1回のリクエストでユーザー情報と注文履歴を同時に取得できます。

AWS AppSyncとは

AWS AppSyncは、GraphQLおよびPub/Sub APIを提供するAWSのフルマネージドサービスです。GraphQLサーバーを自前で構築・運用する手間なく、DynamoDBやAWS Lambda、その他のデータソースと接続したGraphQL APIをすぐに作れます。
本記事ではGraphQL APIの作成を扱います。

API Gateway REST APIとの違い

どちらが良いというわけではなく、ユースケース次第です。シンプルなCRUD APIや既存のLambdaをそのままAPIとして公開したい場合はAmazon API Gatewayの方が向いていると考えられます。一方でフロントエンドからのデータ取得を柔軟にしたい、リアルタイム機能が必要、複数のバックエンドを統合したいといった要件があればAppSyncが向いています。

実際にAPIを作ってみる

ここからはAWSコンソールからAppSyncのAPIを作成していきます。AWSのクイックスタートドキュメントに沿って進めていきます。

AppSyncのGraphQL APIには、3つの主要コンポーネントがあります。

  • スキーマ: APIの設計図。どんな操作(クエリ・ミューテーション)ができるか、どんなデータ型があるかを定義
  • データソース: データの格納先。DynamoDB、Lambdaなどを接続できます
    • Lambdaはデータを保持しているわけではないですが、Lambdaを介してさまざまなデータソースにアクセス可能なため、Lambdaも設定可能となっているようです
  • リゾルバー: スキーマのフィールドとデータソースを繋ぐロジック。JavaScriptランタイム(APPSYNC_JS)で記述します。リゾルバーのランタイムとしてVTL(Velocity Template Language)も選択可能ですが、現在はAPPSYNC_JSが主にサポートされています

We now primarily support the APPSYNC_JS runtime and its documentation.

https://docs.aws.amazon.com/appsync/latest/devguide/tutorials.html

AppSync APIの作成

AWSコンソールからAppSyncを開き、「APIを作成」を選択し、GraphQL APIを選びます。

スクリーンショット 2026-04-18 21.44.00.png

作成方法は複数選択肢がありますが、今回は「Design from scratch」を選択します。

スクリーンショット 2026-04-18 21.47.10.png

API名などはデフォルトにし、「次へ」を押します。
ちなみに、API Gateway同様にPrivate APIも作成できるようですね。

スクリーンショット 2026-04-18 21.48.41.png

次はリソースを定義します。「DynamoDB テーブルを使用するタイプを今すぐ作成」を選択し、モデル名とフィールドを入力します。

スクリーンショット 2026-04-18 21.59.50.png

タイプにはプログラミングで使われるStringやBool以外にもIDやEmailなどが指定できます。

スクリーンショット 2026-04-18 22.01.15.png

この時点では以下のようなスキーマ定義になります。必須のパラメータは型に「!」がつきます。

type Todo {
	id: ID!
	name: String
	when: String
	where: String
	description: String
}

モデルテーブル名を入力します。これが作成されるDynamoDBのテーブル名となります。Primary keyにはidを指定します。

スクリーンショット 2026-04-18 22.04.02.png

最後に確認画面が出るので作成をします。

スクリーンショット 2026-04-18 22.05.30.png

作成されたスキーマなどを確認

スキーマ

作成されたスキーマを確認すると、CreateTodoInputやDeleteTodoInputといったいわゆるCRUD操作に利用するスキーマが自動で定義されます。

input CreateTodoInput {
	name: String
	when: String
	where: String
	description: String
}

input DeleteTodoInput {
	id: ID!
}

input ModelSizeInput {
	ne: Int
	eq: Int
	le: Int
	lt: Int
	ge: Int
	gt: Int
	between: [Int]
}

input TableBooleanFilterInput {
	ne: Boolean
	eq: Boolean
	attributeExists: Boolean
}

input TableFloatFilterInput {
	ne: Float
	eq: Float
	le: Float
	lt: Float
	ge: Float
	gt: Float
	between: [Float]
	attributeExists: Boolean
}

input TableIDFilterInput {
	ne: ID
	eq: ID
	le: ID
	lt: ID
	ge: ID
	gt: ID
	contains: ID
	notContains: ID
	between: [ID]
	beginsWith: ID
	attributeExists: Boolean
	size: ModelSizeInput
}

input TableIntFilterInput {
	ne: Int
	eq: Int
	le: Int
	lt: Int
	ge: Int
	gt: Int
	between: [Int]
	attributeExists: Boolean
}

input TableStringFilterInput {
	ne: String
	eq: String
	le: String
	lt: String
	ge: String
	gt: String
	contains: String
	notContains: String
	between: [String]
	beginsWith: String
	attributeExists: Boolean
	size: ModelSizeInput
}

input TableTodoFilterInput {
	id: TableIDFilterInput
	name: TableStringFilterInput
	when: TableStringFilterInput
	where: TableStringFilterInput
	description: TableStringFilterInput
}

type Todo {
	id: ID!
	name: String
	when: String
	where: String
	description: String
}

type TodoConnection {
	items: [Todo]
	nextToken: String
}

input UpdateTodoInput {
	id: ID!
	name: String
	when: String
	where: String
	description: String
}

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

type Query {
	getTodo(id: ID!): Todo
	listTodos(filter: TableTodoFilterInput, limit: Int, nextToken: String): TodoConnection
}

type Subscription {
	onCreateTodo(
		id: ID,
		name: String,
		when: String,
		where: String,
		description: String
	): Todo
		@aws_subscribe(mutations: ["createTodo"])
	onUpdateTodo(
		id: ID,
		name: String,
		when: String,
		where: String,
		description: String
	): Todo
		@aws_subscribe(mutations: ["updateTodo"])
	onDeleteTodo(
		id: ID,
		name: String,
		when: String,
		where: String,
		description: String
	): Todo
		@aws_subscribe(mutations: ["deleteTodo"])
}

データソース

データソースではDynamoDBが作成されたことを確認できます。

スクリーンショット 2026-04-18 22.12.46.png

クエリ

クエリでは作成したデータソースに対してクエリを行い、テストを行うことができます。

スクリーンショット 2026-04-19 21.01.00.png

試しにVariablesの値を書き換えて、createTodoをしてみます。すると、idが自動で振られ、DynamoDBにもデータが登録されます。

スクリーンショット 2026-04-19 21.02.19.png

スクリーンショット 2026-04-19 21.04.02.png

Deleteのクエリを実行すると、先ほど登録された内容がDynamoDBから削除されていることが確認できました。
スクリーンショット 2026-04-19 21.13.52.png

なお、クエリ作成はExplorerからクエリを作成することもできます。

スクリーンショット 2026-04-19 21.33.45.png

キャッシュ

この時点では作成していませんが、Amazon ElastiCache(Redis OSS)によるキャッシュ層を設定することもできます。これによりAPIのレイテンシー低減に寄与しますが、インスタンスタイプにより時間課金が発生します。

設定

作成されたAPIの詳細情報などが確認できます。ログの設定もこの項目から可能です。

中でもプライマリ認証モードで、APIキーの作成が可能です。(API作成時、APIキーも自動で作成されていました。)

スクリーンショット 2026-04-19 21.23.49.png

API GatewayにもAPIキー(x-api-keyヘッダー)の仕組みはありますが、これは使用量プランの識別が主目的で、認可手段としての利用は推奨されていません。

対してAppSyncでは下記の記載があります。

API キーは、パブリック API の公開が安全であるユースケース、または開発目的での使用が推奨されます。クライアントでは、API キーをヘッダー x-api-key で指定します。

すなわち、用途次第ではAPIキーによる認可も可能と読み取れます。ただ、AppSyncも複数の認可方法が提供されているので、必要に応じて適切な方法を選んだほうが良いでしょう。

クリーンアップ

今回作成したリソースを削除する場合は、AppSyncのAPIを削除すれば紐づくAPIキー・スキーマ・リゾルバーもまとめて削除されます。ただし、DynamoDBのテーブルは別途削除が必要です。

まとめ

Amplifyを使う中で、さりげなく使っているAppSyncについて入門してみましたが、想像よりは簡単に扱えると思いました。一方で、設計思想等を理解する必要がある点や、REST APIと比べるとまだまだ浸透していないと感じる部分もあります。
今後はREST API一択(だからAPI Gateway)というわけではなく、要件に応じて使うことも検討したいです。

参考

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?