翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。
チュートリアル: での 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 では、次の機能が提供されます。
-
Mutation フィールドを使用してペットを作成します。createPet
-
Mutation フィールドを使用してペットを更新します。updatePet
-
Mutation フィールドを使用してペットを削除します。deletePet
-
Query.getPet フィールドを使用してペットを 1 頭取得する
-
Query. フィールドを使用してすべてのペットを一覧表示します。listPets
-
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 } }
レスポンスには、id、type、price が含まれています。
{ "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'