チュートリアル: での Aurora Serverless の使用 AWS AppSync - AWS AppSync

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

チュートリアル: での Aurora Serverless の使用 AWS AppSync

AWS AppSync は、データ で有効になっている Amazon Aurora Serverless クラスターに対してSQLコマンドを実行するためのデータソースを提供しますAPI。 AppSync リゾルバーを使用して、GraphQL クエリ、ミューテーション、サブスクリプションAPIを持つデータに対してSQLステートメントを実行できます。

クラスターを作成する

RDS データソースを に追加する前に、まず Aurora Serverless クラスターAPIでデータを有効にし、 を使用してシークレットを設定 AppSync する必要があります AWS Secrets Manager。Aurora Serverless クラスターは、まず を使用して作成できます AWS CLI。

aws rds create-db-cluster --db-cluster-identifier http-endpoint-test --master-username USERNAME \ --master-user-password COMPLEX_PASSWORD --engine aurora --engine-mode serverless \ --region us-east-1

これにより、クラスターARNの が返されます。

AWS Secrets Manager コンソール、または前のステップCLIの USERNAMEおよび COMPLEX_PASSWORD を使用して、次のような入力ファイルを使用して 経由でシークレットを作成します。

{ "username": "USERNAME", "password": "COMPLEX_PASSWORD" }

これをパラメータとして に渡します AWS CLI。

aws secretsmanager create-secret --name HttpRDSSecret --secret-string file://creds.json --region us-east-1

これにより、シークレットARNの が返されます。

データソースを作成するときは、後でコンソールで使用できるように、Aurora Serverless クラスターARNの とシークレットに注意してください。 AppSync

データを有効にする API

RDS ドキュメント の手順に従って、クラスターAPIで データを有効にできます。をデータソースとして追加する前に、 AppSync データを有効にするAPI必要があります。

データベースとテーブルを作成する

データを有効にしたらAPI、 の aws rds-data execute-statement コマンドで動作するようにできます AWS CLI。これにより、Aurora Serverless クラスターが に追加される前に正しく設定されます AppSync API。まず、 --sqlパラメータTESTDBを使用して という名前のデータベースを作成します。

aws rds-data execute-statement --resource-arn "arn:aws:rds:us-east-1:123456789000:cluster:http-endpoint-test" \ --schema "mysql" --secret-arn "arn:aws:secretsmanager:us-east-1:123456789000:secret:testHttp2-AmNvc1" \ --region us-east-1 --sql "create DATABASE TESTDB"

これがエラーなしで実行されたら、create table コマンドを使用してテーブルを追加します。

aws rds-data execute-statement --resource-arn "arn:aws:rds:us-east-1:123456789000:cluster:http-endpoint-test" \ --schema "mysql" --secret-arn "arn:aws:secretsmanager:us-east-1:123456789000:secret:testHttp2-AmNvc1" \ --region us-east-1 \ --sql "create table Pets(id varchar(200), type varchar(200), price float)" --database "TESTDB"

すべてに問題なく実行された場合は、クラスターを のデータソースとして追加できます AppSync API。

GraphQL スキーマ

Aurora Serverless Data APIがテーブルで稼働しているので、GraphQL スキーマを作成し、ミューテーションとサブスクリプションを実行するためのリゾルバーをアタッチします。 AWS AppSync コンソールAPIで新しい を作成し、スキーマページに移動して、次のように入力します。

type Mutation { createPet(input: CreatePetInput!): Pet updatePet(input: UpdatePetInput!): Pet deletePet(input: DeletePetInput!): Pet } input CreatePetInput { type: PetType price: Float! } input UpdatePetInput { id: ID! type: PetType price: Float! } input DeletePetInput { id: ID! } type Pet { id: ID! type: PetType price: Float } enum PetType { dog cat fish bird gecko } type Query { getPet(id: ID!): Pet listPets: [Pet] listPetsByPriceRange(min: Float, max: Float): [Pet] } schema { query: Query mutation: Mutation }

スキーマを保存し、[データソース] ページに移動して、新しいデータソースを作成します。データソースタイプとして [Relational database (リレーショナルデータベース)] を選択し、データソース名としてわかりやすい名前を入力します。最後のステップで作成したデータベース名と、それを作成したクラスターARNを使用します。ロールでは、 で新しいロール AppSync を作成するか、次のようなポリシーでロールを作成できます。

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "rds-data:DeleteItems", "rds-data:ExecuteSql", "rds-data:ExecuteStatement", "rds-data:GetItems", "rds-data:InsertItems", "rds-data:UpdateItems" ], "Resource": [ "arn:aws:rds:us-east-1:123456789012:cluster:mydbcluster", "arn:aws:rds:us-east-1:123456789012:cluster:mydbcluster:*" ] }, { "Effect": "Allow", "Action": [ "secretsmanager:GetSecretValue" ], "Resource": [ "arn:aws:secretsmanager:us-east-1:123456789012:secret:mysecret", "arn:aws:secretsmanager:us-east-1:123456789012:secret:mysecret:*" ] } ] }

このポリシーには、ロールにアクセス許可を付与する 2 つのステートメントがあります。最初のリソースは Aurora Serverless クラスターで、2 つ目は です AWS Secrets Manager ARN。の作成 をクリックする前に、 AppSync データソース設定BOTHARNsで を指定する必要があります。

リゾルバーの設定

有効な GraphQL スキーマとRDSデータソースができたので、スキーマの GraphQL フィールドにリゾルバーをアタッチできます。API では、次の機能が提供されます。

  1. Mutation フィールドを使用してペットを作成します。createPet

  2. Mutation フィールドを使用してペットを更新します。updatePet

  3. Mutation フィールドを使用してペットを削除します。deletePet

  4. Query.getPet フィールドを使用してペットを 1 頭取得する

  5. Query. フィールドを使用してすべてのペットを一覧表示します。listPets

  6. Query フィールドを使用して、料金範囲内のペットを一覧表示します。listPetsByPriceRange

ミューテーション。createPet

AWS AppSync コンソールのスキーマエディタから、右側の「 のリゾルバーをアタッチする」を選択しますcreatePet(input: CreatePetInput!): Pet。RDS データソースを選択します。[リクエストマッピングテンプレート] セクションで、以下のテンプレートを追加します。

#set($id=$utils.autoId()) { "version": "2018-05-29", "statements": [ "insert into Pets VALUES (:ID, :TYPE, :PRICE)", "select * from Pets WHERE id = :ID" ], "variableMap": { ":ID": "$ctx.args.input.id", ":TYPE": $util.toJson($ctx.args.input.type), ":PRICE": $util.toJson($ctx.args.input.price) } }

SQL ステートメントは、ステートメント配列の順序に基づいて順番に実行されます。結果はその同じ順序で返されます。これはミューテーションなので、挿入の後に選択ステートメントを実行して、GraphQL レスポンスマッピングテンプレートに入力するための、コミットされた値を取得します。

[レスポンスマッピングテンプレート] セクションで、以下のテンプレートを追加します。

$utils.toJson($utils.rds.toJsonObject($ctx.result)[1][0])

ステートメントには 2 つのSQLクエリがあるため、データベースから返される行列に 2 番目の結果を指定する必要があります。 $utils.rds.toJsonString($ctx.result))[1][0])

ミューテーション。updatePet

AWS AppSync コンソールのスキーマエディタから、右側の「 のリゾルバーをアタッチする」を選択しますupdatePet(input: UpdatePetInput!): Pet。RDS データソースを選択します。[リクエストマッピングテンプレート] セクションで、以下のテンプレートを追加します。

{ "version": "2018-05-29", "statements": [ $util.toJson("update Pets set type=:TYPE, price=:PRICE WHERE id=:ID"), $util.toJson("select * from Pets WHERE id = :ID") ], "variableMap": { ":ID": "$ctx.args.input.id", ":TYPE": $util.toJson($ctx.args.input.type), ":PRICE": $util.toJson($ctx.args.input.price) } }

[レスポンスマッピングテンプレート] セクションで、以下のテンプレートを追加します。

$utils.toJson($utils.rds.toJsonObject($ctx.result)[1][0])

ミューテーション。deletePet

AWS AppSync コンソールのスキーマエディタから、右側の「 のリゾルバーをアタッチする」を選択しますdeletePet(input: DeletePetInput!): Pet。RDS データソースを選択します。[リクエストマッピングテンプレート] セクションで、以下のテンプレートを追加します。

{ "version": "2018-05-29", "statements": [ $util.toJson("select * from Pets WHERE id=:ID"), $util.toJson("delete from Pets WHERE id=:ID") ], "variableMap": { ":ID": "$ctx.args.input.id" } }

[レスポンスマッピングテンプレート] セクションで、以下のテンプレートを追加します。

$utils.toJson($utils.rds.toJsonObject($ctx.result)[0][0])

クエリ。getPet

スキーマのミューテーションが作成されたら、3 つのクエリを接続して、個々の項目、リストの取得方法、SQLフィルタリングの適用方法を示します。 AWS AppSync コンソールのスキーマエディタから、右側の「 のリゾルバーをアタッチする」を選択しますgetPet(id: ID!): Pet。RDS データソースを選択します。[リクエストマッピングテンプレート] セクションで、以下のテンプレートを追加します。

{ "version": "2018-05-29", "statements": [ $util.toJson("select * from Pets WHERE id=:ID") ], "variableMap": { ":ID": "$ctx.args.id" } }

[レスポンスマッピングテンプレート] セクションで、以下のテンプレートを追加します。

$utils.toJson($utils.rds.toJsonObject($ctx.result)[0][0])

クエリ。listPets

AWS AppSync コンソールのスキーマエディタから、右側の「 のリゾルバーのアタッチ」を選択しますgetPet(id: ID!): Pet。RDS データソースを選択します。[リクエストマッピングテンプレート] セクションで、以下のテンプレートを追加します。

{ "version": "2018-05-29", "statements": [ "select * from Pets" ] }

[レスポンスマッピングテンプレート] セクションで、以下のテンプレートを追加します。

$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])

クエリ。listPetsByPriceRange

AWS AppSync コンソールのスキーマエディタから、右側の「 のリゾルバーのアタッチ」を選択しますgetPet(id: ID!): Pet。RDS データソースを選択します。[リクエストマッピングテンプレート] セクションで、以下のテンプレートを追加します。

{ "version": "2018-05-29", "statements": [ "select * from Pets where price > :MIN and price < :MAX" ], "variableMap": { ":MAX": $util.toJson($ctx.args.max), ":MIN": $util.toJson($ctx.args.min) } }

[レスポンスマッピングテンプレート] セクションで、以下のテンプレートを追加します。

$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])

ミューテーションを実行する

すべてのリゾルバーに SQLステートメントを設定し、GraphQL APIを Serverless Aurora Data に接続したのでAPI、ミューテーションとクエリの実行を開始できます。 AWS AppSync コンソールでクエリタブを選択し、次のように入力してペットを作成します。

mutation add { createPet(input : { type:fish, price:10.0 }){ id type price } }

レスポンスには、idtypeprice が含まれています。

{ "data": { "createPet": { "id": "c6fedbbe-57ad-4da3-860a-ffe8d039882a", "type": "fish", "price": "10.0" } } }

updatePet ミューテーションを実行することで、この項目を変更できます。

mutation update { updatePet(input : { id: ID_PLACEHOLDER, type:bird, price:50.0 }){ id type price } }

前に createPetオペレーションから返された ID を使用したことに注意してください。リゾルバーが $util.autoId() を利用したため、これがレコードに固有の値になります。同様の方法でレコードを削除できます。

mutation delete { deletePet(input : {id:ID_PLACEHOLDER}){ id type price } }

最初のミューテーションで price に異なる値を使用してレコードをいくつか作成したら、クエリをいくつか実行します。

クエリを実行する

引き続きコンソールの [クエリ] タブで、以下のステートメントを使用して、作成したすべてのレコードを一覧表示します。

query allpets { listPets { id type price } }

これは良いことですが、次の GraphQL クエリを使用して、クエリlistPetsByPriceRangeのマッピングテンプレートwhere price > :MIN and price < :MAXに が置いたSQLWHERE述語を活用しましょう。

query petsByPriceRange { listPetsByPriceRange(min:1, max:11) { id type price } }

price が 1 ドル以上、10 ドル未満のレコードのみが表示されます。最後に、以下のようにクエリを実行して個々のレコードを取得できます。

query onePet { getPet(id:ID_PLACEHOLDER){ id type price } }

入力サニタイズ

デベロッパーは、SQLインジェクション攻撃から保護variableMapするために を使用することをお勧めします。変数マップを使用しない場合、開発者は GraphQL 操作の引数をサニタイズする責任があります。これを行う 1 つの方法は、データ に対してSQLステートメントを実行する前に、リクエストマッピングテンプレートに入力固有の検証ステップを提供することですAPI。listPetsByPriceRange 例のリクエストマッピングテンプレートを変更する方法を見てみましょう。ユーザー入力だけに頼るのではなく、以下のことが可能です。

#set($validMaxPrice = $util.matches("\d{1,3}[,\\.]?(\\d{1,2})?",$ctx.args.maxPrice)) #set($validMinPrice = $util.matches("\d{1,3}[,\\.]?(\\d{1,2})?",$ctx.args.minPrice)) #if (!$validMaxPrice || !$validMinPrice) $util.error("Provided price input is not valid.") #end { "version": "2018-05-29", "statements": [ "select * from Pets where price > :MIN and price < :MAX" ], "variableMap": { ":MAX": $util.toJson($ctx.args.maxPrice), ":MIN": $util.toJson($ctx.args.minPrice) } }

データに対してリゾルバーを実行するときに不正な入力から保護するもう 1 つの方法は、ストアドプロシージャとパラメータ化された入力とともにプリペアドステートメントを使用することAPIです。例えば、listPets のリゾルバーで、select をプリペアードステートメントとして実行する以下のプロシージャを定義します。

CREATE PROCEDURE listPets (IN type_param VARCHAR(200)) BEGIN PREPARE stmt FROM 'SELECT * FROM Pets where type=?'; SET @type = type_param; EXECUTE stmt USING @type; DEALLOCATE PREPARE stmt; END

これは、以下の execute sql コマンドを使用して、Aurora Serverless インスタンスに作成できます。

aws rds-data execute-statement --resource-arn "arn:aws:rds:us-east-1:xxxxxxxxxxxx:cluster:http-endpoint-test" \ --schema "mysql" --secret-arn "arn:aws:secretsmanager:us-east-1:xxxxxxxxxxxx:secret:httpendpoint-xxxxxx" \ --region us-east-1 --database "DB_NAME" \ --sql "CREATE PROCEDURE listPets (IN type_param VARCHAR(200)) BEGIN PREPARE stmt FROM 'SELECT * FROM Pets where type=?'; SET @type = type_param; EXECUTE stmt USING @type; DEALLOCATE PREPARE stmt; END"

ストアドプロシージャを呼び出すだけで済むようになったため、 の結果のリゾルバーコード listPets が簡略化されました。少なくとも、文字列入力では一重引用符をエスケープする必要があります。

#set ($validType = $util.isString($ctx.args.type) && !$util.isNullOrBlank($ctx.args.type)) #if (!$validType) $util.error("Input for 'type' is not valid.", "ValidationError") #end { "version": "2018-05-29", "statements": [ "CALL listPets(:type)" ] "variableMap": { ":type": $util.toJson($ctx.args.type.replace("'", "''")) } }

文字列のエスケープ

一重引用符は、 などの SQLステートメント内の文字列リテラルの開始と終了を表します'some string value'。1 つ以上の一重引用符 (') を含む文字列値を文字列内で使用するには、それぞれを 2 つの一重引用符 ('') に置き換える必要があります。例えば、入力文字列が の場合Nadia's dog、 のように SQLステートメントに対してエスケープします。

update Pets set type='Nadia''s dog' WHERE id='1'