本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
教程:Aurora Serverless
Amazon AppSync提供了一个数据源,用于针对已使用数据 API 启用的 Amazon Aurora Serverless 集群执行 SQL 命令。您可以使用 AppSync 解析程序通过 GraphQL 查询、更改和订阅对数据 API 执行 SQL 语句。
创建集群
在将 RDS 数据源添加到 AppSync 之前,您必须先在 Aurora Serverless 集群上启用数据 API 并且配置密钥使用Amazon Secrets Manager. 您可以先使用此方式创建 Aurora Serverless 集群。Amazon 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。
通过创建密钥Amazon Secrets Manager使用上一步中的 USERNAME 和 COPLEZ_PASSWORD,通过控制台或通过包含类似于以下内容的输入文件的 CLI:
{ "username": "USERNAME", "password": "COMPLEX_PASSWORD" }
将此内容作为参数传递到Amazon CLI:
aws secretsmanager create-secret --name HttpRDSSecret --secret-string file://creds.json --region us-east-1
这将为密钥返回 ARN。
记下稍后在创建数据源时在 AppSync 控制台中使用的 Aurora Serverless 集群和密钥的 ARN。
启用数据 API
您可以通过按照 RDS 文档中的说明操作来在您的集群上启用数据 API。在将数据 API 作为 AppSync 数据源添加之前,必须先启用它。
创建数据库和表
在启用数据 API 后,您可以确保它与aws
rds-data execute-statement
中的命令Amazon CLI. 这将确保在将 Aurora Serverless 集群添加到 AppSync API 之前已进行正确配置。首先创建一个名为TESTDB使用--sql
像这样的参数:
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"
如果运行无误,请使用创建表 命令添加一个表:
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 数据 API 已通过表启动并运行,我们将创建一个 GraphQL 架构并附加用于执行更改和订阅的解析程序。在中创建新 APIAmazon AppSync控制台并导航到架构页面,并输入以下内容:
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 }
保存您的架构并导航到数据源页面,然后创建新的数据源。为数据源类型选择关系数据库,并提供一个友好名称。使用您在上一步中创建的数据库名称以及用来创建它的集群 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:*" ] } ] }
请注意,此策略中有两个需要获得角色访问权的语句。第一个资源是您的 Aurora Serverless 集群,第二个集群是您的Amazon Secrets ManagerARN。您需要提供都在单击之前,AppSync 数据源配置中的 ARNCreate.
配置解析程序
现在,我们有一个有效的 GraphQL 架构和一个 RDS 数据源,我们可以将解析程序附加到架构上的 GraphQL 字段。我们的 API 将提供以下功能:
-
通过 Mutation.createPet 字段创建宠物
-
通过 Mutation.updatePet 字段更新宠物
-
通过 Mutation.deletePet 字段删除宠物
-
通过 Query.getPet 字段获取单个宠物
-
通过 Query.listPets 字段列出所有宠物
-
通过 Query.listPetsByPriceRange 字段列出价格范围内的宠物
Mutation.createPet
从中的模式编辑器Amazon在 AppSync 控制台上,选择右侧的附加解析程序为了createPet(input:
CreatePetInput!): Pet
. 选择您的 RDS 数据源。在 request mapping template (请求映射模板) 部分中,添加以下模板:
#set($id=$utils.autoId()) { "version": "2018-05-29", "statements": [ "insert into Pets VALUES ('$id', '$ctx.args.input.type', $ctx.args.input.price)", "select * from Pets WHERE id = '$id'" ] }
SQL 语句将根据语句数组中的顺序依次执行。结果将以相同的顺序返回。由于这是一种突变,我们运行选择之后的声明插入以检索已提交的值以填充 GraphQL 响应映射模板。
在 response mapping template (响应映射模板) 部分中,添加以下模板:
$utils.toJson($utils.rds.toJsonObject($ctx.result)[1][0])
由于语句有两个 SQL 查询,我们需要指定从具有 $utils.rds.toJsonString($ctx.result))[1][0])
的数据库返回的矩阵中的第二个结果。
Mutation.updatePet
从中的模式编辑器Amazon在 AppSync 控制台上,选择右侧的附加解析程序为了updatePet(input:
UpdatePetInput!): Pet
. 选择您的 RDS 数据源。在 request mapping template (请求映射模板) 部分中,添加以下模板:
{ "version": "2018-05-29", "statements": [ $util.toJson("update Pets set type='$ctx.args.input.type', price=$ctx.args.input.price WHERE id='$ctx.args.input.id'"), $util.toJson("select * from Pets WHERE id = '$ctx.args.input.id'") ] }
在 response mapping template (响应映射模板) 部分中,添加以下模板:
$utils.toJson($utils.rds.toJsonObject($ctx.result)[1][0])
Mutation.deletePet
从中的模式编辑器Amazon在 AppSync 控制台上,选择右侧的附加解析程序为了deletePet(input:
DeletePetInput!): Pet
. 选择您的 RDS 数据源。在 request mapping template (请求映射模板) 部分中,添加以下模板:
{ "version": "2018-05-29", "statements": [ $util.toJson("select * from Pets WHERE id='$ctx.args.input.id'"), $util.toJson("delete from Pets WHERE id='$ctx.args.input.id'") ] }
在 response mapping template (响应映射模板) 部分中,添加以下模板:
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0][0])
Query.getPet
现在,已为您的架构创建更改,我们将连接三个查询以展示如何获取各个项目和列表以及应用 SQL 筛选。从中的模式编辑器Amazon在 AppSync 控制台上,选择右侧的附加解析程序为了getPet(id: ID!): Pet
. 选择您的 RDS 数据源。在 request mapping template (请求映射模板) 部分中,添加以下模板:
{ "version": "2018-05-29", "statements": [ $util.toJson("select * from Pets WHERE id='$ctx.args.id'") ] }
在 response mapping template (响应映射模板) 部分中,添加以下模板:
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0][0])
Query.listPets
从中的模式编辑器Amazon在 AppSync 控制台上,选择右侧的附加解析程序为了getPet(id: ID!):
Pet
. 选择您的 RDS 数据源。在 request mapping template (请求映射模板) 部分中,添加以下模板:
{ "version": "2018-05-29", "statements": [ "select * from Pets" ] }
在 response mapping template (响应映射模板) 部分中,添加以下模板:
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])
Query.listPetsByPriceRange
从中的模式编辑器Amazon在 AppSync 控制台上,选择右侧的附加解析程序为了getPet(id: ID!):
Pet
. 选择您的 RDS 数据源。在 request mapping template (请求映射模板) 部分中,添加以下模板:
{ "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) } }
在 response mapping template (响应映射模板) 部分中,添加以下模板:
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])
运行更改
现在,您已使用 SQL 语句配置所有解析程序并将 GraphQL API 连接到 Serverless Aurora 数据 API,可以开始执行更改和查询。InAmazonAppSync 控制台,选择查询选项卡并输入以下内容来创建宠物:
mutation add { createPet(input : { type:fish, price:10.0 }){ id type price } }
该响应包含 id、类型 和价格,如下所示:
{ "data": { "createPet": { "id": "c6fedbbe-57ad-4da3-860a-ffe8d039882a", "type": "fish", "price": "10.0" } } }
您可以通过运行 updatePet 更改来修改此项目:
mutation update { updatePet(input : { id:"c6fedbbe-57ad-4da3-860a-ffe8d039882a", type:bird, price:50.0 }){ id type price } }
请注意,我们使用了id这是从createPet操作之前。当解析程序利用 $util.autoId()
时,这将是您的记录的唯一值。您可以通过类似的方式删除记录:
mutation { deletePet(input : {id:ID_PLACEHOLDER}){ id type price } }
使用包含不同的价格 值的第一个更改创建几条记录,然后运行几个查询。
运行查询
同样,在控制台的查询选项卡中,使用以下语句列出您创建的所有记录:
query allpets { listPets { id type price } }
这很不错但是让我们利用 SQL哪里谓词where price > :MIN and price <
:MAX
在我们的映射模板中Query.listPetsByPriceRange使用以下 GraphQL 查询:
query { listPetsByPriceRange(min:1, max:11) { id type price } }
您应仅看到包含高于 1 美元或低于 10 美元的价格 的记录。最后,您可以执行查询以检索各个记录,如下所示:
query { getPet(id:ID_PLACEHOLDER){ id type price } }
输入净化
我们强烈建议开发人员清理 GraphQL 操作的参数。执行此操作的一种方法是在对数据 API 执行 SQL 语句之前,在请求映射模板中提供特定于输入的验证步骤。让我们看看如何修改 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) } }
在对数据 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'
。要允许在字符串中使用具有一个或多个单引号字符 ( '
) 的字符串值,必须用两个单引号 (''
) 替换每个字符串值。例如,如果输入字符串是 Nadia's dog
,您可以针对 SQL 语句将其转义,例如
update Pets set type='Nadia''s dog' WHERE id='1'