翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。
AWS AppSync でのパイプラインリゾルバーの使用
注記
現在、主に APPSYNC_JS ランタイムとそのドキュメントをサポートしています。こちらにある APPSYNC_JS ランタイムとそのガイドの使用をご検討ください。
AWS AppSync は、GraphQL フィールドをユニットリゾルバー経由で 1 つのデータソースにつなぐシンプルな方法を提供します。ただし、1 つのオペレーションを実行するだけでは不十分な場合があります。パイプラインリゾルバーは、データソースに対してオペレーションを順番に実行する機能を提供します。API で関数を作成し、パイプラインリゾルバーにアタッチします。各関数の実行結果は、実行する関数がなくなるまで、次の結果にパイプされます。パイプラインリゾルバーを使用すると、AWS AppSync で直接、より複雑なワークフローを構築できます。このチュートリアルでは、友人によって投稿された写真を投稿したり表示したりできる、シンプルな写真表示アプリケーションを作成します。
ワンクリックでのセットアップ
設定したすべてのリゾルバーと必要な AWS リソースを使用して AWS AppSync に GraphQL エンドポイントが自動的に設定されるようにする場合は、以下の AWS CloudFormation テンプレートを使用できます。
このスタックはお客様のアカウントに以下のリソースを作成します。
-
AWS AppSync がお客様のアカウントのリソースにアクセスするための IAM ロール
-
2 DynamoDB テーブル
-
1 つの Amazon Cognito ユーザープール
-
2 つの Amazon Cognito ユーザープールグループ
-
3 つの Amazon Cognito ユーザープールユーザー
-
1 AWS AppSync API
AWS CloudFormation スタック作成プロセスの最後に、作成された 3 つの Amazon Cognito ユーザーごとに 1 件の E メールを受信します。各 E メールには、Amazon Cognito ユーザーとして AWS AppSync コンソールにログインするために使用する一時パスワードが含まれています。これらのパスワードを保存し、チュートリアルの残りで使用します。
手動セットアップ
AWS AppSync コンソールからステップバイステップのプロセスを手動で実行する場合は、以下の設定プロセスに従います。
AWS AppSync リソース以外のリソースの設定
API は、2 つの DynamoDB テーブル (写真を保存する pictures テーブルおよびユーザー間の関係を保存する friends テーブル) とやり取りします。API は、認証タイプとして Amazon Cognito ユーザープールを使用するように設定されています。以下の AWS CloudFormation スタックはアカウント内にこれらのリソースを設定します。
AWS CloudFormation スタック作成プロセスの最後に、作成された 3 つの Amazon Cognito ユーザーごとに 1 件の E メールを受信します。各 E メールには、Amazon Cognito ユーザーとして AWS AppSync コンソールにログインするために使用する一時パスワードが含まれています。これらのパスワードを保存し、チュートリアルの残りで使用します。
GraphQL API の作成
AWS AppSync で GraphQL API を作成するには、以下の手順に従います。
-
AWS AppSync コンソールを開き、[Build From Scratch (最初から構築)]、[Start (開始)] の順に選択します。
-
API の名前を
AppSyncTutorial-PicturesViewer
に設定します。 -
[Create] (作成) を選択します。
AWS AppSync コンソールによって、API キー認証モードを使用して新しい GraphQL API が作成されます。このコンソールを使用して、残りの GraphQL API をセットアップでき、このチュートリアルの残りの部分でクエリを実行できます。
GraphQL API の設定
先ほど作成した Amazon Cognito ユーザープールを使用して AWS AppSync API を設定する必要があります。
-
[Settings] (設定) タブを選択します。
-
[Authorization Type (承認タイプ)] セクションで、Amazon Cognito ユーザープールを選択します。
-
[ユーザープールの設定] で、AWSリージョンにUS-WEST-2を選択します。
-
AppSyncTutorial-UserPool ユーザープールを選択します。
-
デフォルトアクションとして拒否を選択します。
-
[AppId client regex (AppId クライアント正規表現)] フィールドは空白のままにします。
-
[Save] を選択します。
これで、承認タイプとして Amazon Cognito ユーザープールを使用するように API が設定されました。
DynamoDB テーブル用のデータソースの設定
DynamoDB テーブルを作成した後、コンソールで AWS AppSync GraphQL API に移動し、[データソース] タブを選択します。次は、先ほど作成した DynamoDB テーブルごとに、AWS AppSync でデータソースを作成します。
-
[Data source (データソース)] タブを選択します。
-
[New (新規)] を選択して、新しいデータソースを作成します。
-
データソース名に、
PicturesDynamoDBTable
を入力します。 -
データソースのタイプとして [Amazon DynamoDB Table (Amazon DynamoDB テーブル)] を選択します。
-
リージョンとして [US-WEST-2 (米国西部 (オレゴン))] を選択します。
-
テーブルのリストから AppSyncTutorial-Pictures DynamoDB テーブルを選択します。
-
「Create or use an existing role (作成または既存のロールの使用)」セクションで [Existing role (既存のロール)] を選択します。
-
CloudFormation テンプレートから先ほど作成したロールを選択します。ResourceNamePrefix を変更しなかった場合、ロールの名前は AppSyncTutorial-DynamoDBRole になっています。
-
[Create] (作成) を選択します。
friendsテーブルについても同じプロセスを繰り返します。CloudFormation スタックの作成時のResourceNamePrefixパラメータを変更しなかった場合、DynamoDB テーブルの名前はAppSyncTutorial-Friendsになります。
GraphQL スキーマの作成
データソースが DynamoDB テーブルに接続されたところで、GraphQL スキーマを作成しましょう。AWS AppSync コンソールのスキーマエディタで、スキーマが以下のスキーマと一致することを確認します。
schema { query: Query mutation: Mutation } type Mutation { createPicture(input: CreatePictureInput!): Picture! @aws_auth(cognito_groups: ["Admins"]) createFriendship(id: ID!, target: ID!): Boolean @aws_auth(cognito_groups: ["Admins"]) } type Query { getPicturesByOwner(id: ID!): [Picture] @aws_auth(cognito_groups: ["Admins", "Viewers"]) } type Picture { id: ID! owner: ID! src: String } input CreatePictureInput { owner: ID! src: String! }
スキーマを保存するには、[Save Schema (スキーマの保存)] を選択します。
いくつかのスキーマフィールドには @aws_auth ディレクティブで注釈が付けられています。API のデフォルトのアクション設定は [拒否] に設定されているため、API は @aws_auth ディレクティブ内で指定されているグループのメンバーではないすべてのユーザーを拒否します。API の保護方法の詳細については、「セキュリティ」ページを参照してください。この場合、管理者ユーザーのみが Mutation.createPicture および Mutation.createFriendship フィールドにアクセスできますが、Admins または Viewers グループのメンバーであるユーザーは Query.getPicturesByOwner フィールドにアクセスできます。他のすべてのユーザーはアクセスできません。
リゾルバーの設定
有効な GraphQL スキーマと 2 つのデータソースを用意できたところで、スキーマでリゾルバーを GraphQL フィールドにアタッチできます。API は以下の機能を提供します。
-
Mutation.createPicture フィールドで写真を作成する
-
Mutation.createFriendship フィールドで友人関係を作成する
-
Query.getPicture フィールドで写真を取得する
Mutation.createPicture
AWS AppSync コンソールのスキーマエディタで、createPicture(input:
CreatePictureInput!): Picture!
のために、右側にある [Attach Resolver (リゾルバーをアタッチ)] を選択します。DynamoDB PicturesDynamoDBTableデータソースを選択します。[リクエストマッピングテンプレート] セクションで、以下のテンプレートを追加します。
#set($id = $util.autoId()) { "version" : "2018-05-29", "operation" : "PutItem", "key" : { "id" : $util.dynamodb.toDynamoDBJson($id), "owner": $util.dynamodb.toDynamoDBJson($ctx.args.input.owner) }, "attributeValues" : $util.dynamodb.toMapValuesJson($ctx.args.input) }
[レスポンスマッピングテンプレート] セクションで、以下のテンプレートを追加します。
#if($ctx.error) $util.error($ctx.error.message, $ctx.error.type) #end $util.toJson($ctx.result)
写真の作成機能が実行されます。ランダムに生成された UUID を写真の ID として使用し、Cognito のユーザー名を写真の所有者として使用して、Pictures テーブルに写真を保存します。
Mutation.createFriendship
AWS AppSync コンソールのスキーマエディタで、createFriendship(id:
ID!, target: ID!): Boolean
のために、右側にある [Attach Resolver (リゾルバーをアタッチ)] を選択します。DynamoDB FriendsDynamoDBTableデータソースを選択します。[リクエストマッピングテンプレート] セクションで、以下のテンプレートを追加します。
#set($userToFriendFriendship = { "userId" : "$ctx.args.id", "friendId": "$ctx.args.target" }) #set($friendToUserFriendship = { "userId" : "$ctx.args.target", "friendId": "$ctx.args.id" }) #set($friendsItems = [$util.dynamodb.toMapValues($userToFriendFriendship), $util.dynamodb.toMapValues($friendToUserFriendship)]) { "version" : "2018-05-29", "operation" : "BatchPutItem", "tables" : { ## Replace 'AppSyncTutorial-' default below with the ResourceNamePrefix you provided in the CloudFormation template "AppSyncTutorial-Friends": $util.toJson($friendsItems) } }
重要: BatchPutItem リクエストテンプレートには、DynamoDB テーブルの正確な名前が指定されている必要があります。デフォルトのテーブル名は AppSyncTutorial-Friends です。間違ったテーブル名を使用している場合、指定したロールを AppSync が引き受けようとするとエラーが発生します。
このチュートリアルでは、シンプルにすることを目的に、友人関係のリクエストが承認されたかのように処理を進め、関係のエントリを AppSyncTutorialFriends テーブルに直接保存します。
実際、友人関係は双方向であるため、関係ごとに 2 つの項目を保存します。多対多の関係を表すための Amazon DynamoDB のベストプラクティスの詳細については、「DynamoDB のベストプラクティス」を参照してください。
[レスポンスマッピングテンプレート] セクションで、以下のテンプレートを追加します。
#if($ctx.error) $util.error($ctx.error.message, $ctx.error.type) #end true
注意: リクエストテンプレートに正しいテーブル名が含まれていることを確認してください。デフォルト名は AppSyncTutorial-Friends ですが、CloudFormation の ResourceNamePrefix パラメータを変更した場合、そのテーブル名が異なることがあります。
Query.getPicturesByOwner
友人関係と写真を用意できたところで、ユーザーが自分の友人の写真を表示できるようにする必要があります。この要件を満たすには、まずリクエスト者が所有者と友人であることを確認し、最後に写真のクエリを実行する必要があります。
この機能には 2 つのデータソースオペレーションが必要であるため、2 つの関数を作成します。最初の関数 isFriend は、リクエスト者と所有者が友人であるかどうかを確認します。2 番目の関数 getPicturesByOwner は、所有者 ID を指定してリクエストされた写真を取得します。Query.getPicturesByOwner フィールドで提案されたリゾルバーに対する以下の実行フローを見てみましょう。
-
Before マッピングテンプレート: コンテキストとフィールドの入力引数を準備します。
-
isFriend 関数: リクエスト者が写真の所有者かどうかを確認します。そうでない場合は、friends テーブルに対して DynamoDB GetItem オペレーションを実行して、リスクエスト者と所有者が友人であるかどうかを確認します。
-
GetPicturebyOwner 関数: owner-indexグローバルセカンダリインデックスの DynamoDB クエリ操作を使用して、ピクチャテーブルから画像を取得します。
-
After マッピングテンプレート: DynamoDB 属性が、想定される GraphQL タイプのフィールドに正しくマッピングされるように、写真の結果をマッピングします。
まず、関数を作成しましょう。
isFriend 関数
-
[関数] タブをクリックします。
-
[関数の作成] を選択して、関数を作成します。
-
データソース名に、
FriendsDynamoDBTable
を入力します。 -
関数名として、「isFriend」と入力します。
-
リクエストマッピングテンプレートのテキスト領域内に、以下のテンプレートを貼り付けます。
#set($ownerId = $ctx.prev.result.owner) #set($callerId = $ctx.prev.result.callerId) ## if the owner is the caller, no need to make the check #if($ownerId == $callerId) #return($ctx.prev.result) #end { "version" : "2018-05-29", "operation" : "GetItem", "key" : { "userId" : $util.dynamodb.toDynamoDBJson($callerId), "friendId" : $util.dynamodb.toDynamoDBJson($ownerId) } }
-
レスポンスマッピングテンプレートのテキスト領域内に、以下のテンプレートを貼り付けます。
#if($ctx.error) $util.error("Unable to retrieve friend mapping message: ${ctx.error.message}", $ctx.error.type) #end ## if the users aren't friends #if(!$ctx.result) $util.unauthorized() #end $util.toJson($ctx.prev.result)
-
[関数の作成] を選択します。
結果: isFriend 関数を作成しました。
getPicturesByOwner 関数
-
[関数] タブをクリックします。
-
[関数の作成] を選択して、関数を作成します。
-
データソース名に、
PicturesDynamoDBTable
を入力します。 -
関数名として、「
getPicturesByOwner
」と入力します。 -
リクエストマッピングテンプレートのテキスト領域内に、以下のテンプレートを貼り付けます。
{ "version" : "2018-05-29", "operation" : "Query", "query" : { "expression": "#owner = :owner", "expressionNames": { "#owner" : "owner" }, "expressionValues" : { ":owner" : $util.dynamodb.toDynamoDBJson($ctx.prev.result.owner) } }, "index": "owner-index" }
-
レスポンスマッピングテンプレートのテキスト領域内に、以下のテンプレートを貼り付けます。
#if($ctx.error) $util.error($ctx.error.message, $ctx.error.type) #end $util.toJson($ctx.result)
-
[関数の作成] を選択します。
結果: getPicturesByOwner 関数を作成しました。関数が作成されたところで、パイプラインリゾルバーを Query.getPicturesByOwner フィールドにアタッチします。
AWS AppSync コンソールのスキーマエディタで、Query.getPicturesByOwner(id: ID!): [Picture]
のために、右側にある [Attach Resolver (リゾルバーをアタッチ)] を選択します。以下のページで、データソースのドロップダウンリストの下に表示される [Convert to pipeline resolver (パイプラインリゾルバーに変換)] リンクを選択します。Before マッピングテンプレートに、以下のものを使用します。
#set($result = { "owner": $ctx.args.id, "callerId": $ctx.identity.username }) $util.toJson($result)
After マッピングテンプレートのセクションに、以下のものを使用します。
#foreach($picture in $ctx.result.items) ## prepend "src://" to picture.src property #set($picture['src'] = "src://${picture['src']}") #end $util.toJson($ctx.result.items)
[Create Resolver (リゾルバー作成)] を選択します。最初のパイプラインリゾルバーが正常にアタッチされました。同じページで、前に作成した 2 つの関数を追加します。関数セクションで、[Add A Function (関数の追加)] を選択してから、最初の関数の名前として [isFriend] を選択または入力します。getPicturesByOwner 関数のものと同じプロセスに従って、2 番目の関数を追加します。isFriend 関数がリストの最初に表示され、続いて getPicturesByOwner 関数が表示されていることを確認します。上下の矢印を使用して、パイプライン内の関数の実行順序に並べ替えることができます。
パイプラインリゾルバーが作成され、関数がアタッチされたところで、新しく作成した GraphQL API をテストしましょう。
GraphQL API をテストする
まず、作成した管理者ユーザーを使用していくつかのミューテーションを実行することで、写真と友人関係を入力する必要があります。AWS AppSync コンソールの左側で、[クエリ] タブを選択します。
createPicture ミューテーション
-
AWS AppSync コンソールで、[クエリ] タブを選択します。
-
[Login With User Pools (ユーザープールでログイン)] を選択します。
-
モーダルで、CloudFormation スタックによって作成された Cognito Sample Client ID (37solo6mmhh7k4v63cqdfgdg5d など) を入力します。
-
CloudFormation スタックにパラメータとして渡したユーザー名を入力します。デフォルトは nadia です。
-
E メールに送信されて CloudFormation スタックへのパラメータとして渡した一時パスワード (UserPoolUserEmail など) を使用します。
-
[ログイン] を選択します。これで、ボタンの名前が Logout nadia に変更されているか、CloudFormation スタックの作成時に選択したユーザー名 (つまり UserPoolUsername) に変更されています。
pictures テーブルに入力するいくつかの createPicture ミューテーションを送信しましょう。コンソール内で以下の GraphQL クエリを実行します。
mutation { createPicture(input:{ owner: "nadia" src: "nadia.jpg" }) { id owner src } }
レスポンスは以下のようになります。
{ "data": { "createPicture": { "id": "c6fedbbe-57ad-4da3-860a-ffe8d039882a", "owner": "nadia", "src": "nadia.jpg" } } }
さらに写真をいくつか追加しましょう。
mutation { createPicture(input:{ owner: "shaggy" src: "shaggy.jpg" }) { id owner src } }
mutation { createPicture(input:{ owner: "rex" src: "rex.jpg" }) { id owner src } }
管理者ユーザーとして nadia を使用して 3 つの写真を追加しました。
createFriendship ミューテーション
友人関係エントリを追加しましょう。コンソールで以下のミューテーションを実行します。
注意: 管理者ユーザーとしてログインしている必要があります (デフォルトの管理者ユーザーは nadia です)。
mutation { createFriendship(id: "nadia", target: "shaggy") }
レスポンスは以下のようになります。
{ "data": { "createFriendship": true } }
nadia と shaggy は友人です。rex はだれとも友人ではありません。
getPicturesByOwner クエリ
この手順では、Cognito ユーザープールと共に、このチュートリアルの始めに設定した認証情報を使用して、nadia ユーザーとしてログインします。nadia として、shaggy が所有する写真を取得します。
query { getPicturesByOwner(id: "shaggy") { id owner src } }
nadia と shaggy は友人であるため、クエリからは対応する写真が返されます。
{ "data": { "getPicturesByOwner": [ { "id": "05a16fba-cc29-41ee-a8d5-4e791f4f1079", "owner": "shaggy", "src": "src://shaggy.jpg" } ] } }
同様に、nadia が自分の写真を取得しようとした場合も、クエリは成功します。その場合、isFriend GetItem オペレーションを実行しないように、パイプラインリゾルバーは最適化されています。以下のクエリを試します。
query { getPicturesByOwner(id: "nadia") { id owner src } }
API のログ記録を有効にしている場合 ([Settings (設定)] ペインで)、デバッグレベルを [すべて] に設定し、同じクエリをもう一度実行すると、フィールド実行のログが返されます。ログを見ることで、リクエストマッピングテンプレートステージでisFriend関数が早期に返されたかどうか判断することができます。
{ "errors": [], "mappingTemplateType": "Request Mapping", "path": "[getPicturesByOwner]", "resolverArn": "arn:aws:appsync:us-west-2:XXXX:apis/XXXX/types/Query/fields/getPicturesByOwner", "functionArn": "arn:aws:appsync:us-west-2:XXXX:apis/XXXX/functions/o2f42p2jrfdl3dw7s6xub2csdfs", "functionName": "isFriend", "earlyReturnedValue": { "owner": "nadia", "callerId": "nadia" }, "context": { "arguments": { "id": "nadia" }, "prev": { "result": { "owner": "nadia", "callerId": "nadia" } }, "stash": {}, "outErrors": [] }, "fieldInError": false }
earlyReturnedValue キーは、#return ディレクティブによって返されたデータを表します。
最後に、rex は Viewers Cognito ユーザープールグループのメンバーです。rex はだれとも友人ではないため、shaggy または nadia によって所有されている写真にアクセスすることはできません。コンソールに rex としてログインし、以下のクエリを実行したとします。
query { getPicturesByOwner(id: "nadia") { id owner src } }
以下の未承認エラーが発生します。
{ "data": { "getPicturesByOwner": null }, "errors": [ { "path": [ "getPicturesByOwner" ], "data": null, "errorType": "Unauthorized", "errorInfo": null, "locations": [ { "line": 2, "column": 9, "sourceName": null } ], "message": "Not Authorized to access getPicturesByOwner on type Query" } ] }
パイプラインリゾルバーを使用した複雑な承認が正常に実装されました。