我在CloudFormation模板(用YAML编写)中提供了一些DynamoDB表资源,在模板的其他地方提供了AppSync端点。
我没有指定表的名称,而是让CloudFormation为它们生成名称。每当需要指定表名时,我都会使用
!Ref TableName
我想在AppSync中使用DynamoDB批处理解析器,这要求我列出表的名称,但是在更新堆栈时,“!Ref TableName”不会转换为表的名称。解析器仅以“!Ref TableName”作为表名结束。
有没有办法将CloudFormation生成的表的名称转换为AppSync模板语言?
下面是我的CloudFormation模板,已针对相关性进行了修剪:
conversationsTable:
Type: "AWS::DynamoDB::Table"
Properties:
AttributeDefinitions:
-
AttributeName: "id"
AttributeType: "S"
KeySchema:
-
AttributeName: "id"
KeyType: "HASH"
ProvisionedThroughput:
ReadCapacityUnits: "1"
WriteCapacityUnits: "1"
userConversationsTable:
Type: "AWS::DynamoDB::Table"
Properties:
AttributeDefinitions:
-
AttributeName: "userId"
AttributeType: "S"
-
AttributeName: "conversationId"
AttributeType: "S"
KeySchema:
-
AttributeName: "userId"
KeyType: "HASH"
-
AttributeName: "conversationId"
KeyType: "RANGE"
ProvisionedThroughput:
ReadCapacityUnits: "1"
WriteCapacityUnits: "1"
...
createConversationMutationResolver:
Type: "AWS::AppSync::Resolver"
Properties:
ApiId: !GetAtt chatQLApi.ApiId
TypeName: "Mutation"
FieldName: "createConversation"
DataSourceName: !GetAtt conversationsTableDataSource.Name
RequestMappingTemplate: |
{
"version" : "2018-05-29",
"operation" : "BatchPutItem",
"tables": {
!Ref conversationsTable : $util.toJson($convoList),
!Ref userConversationsTable : $util.toJson($users)
}
}
ResponseMappingTemplate: |
#if($context.error)
$util.appendError($context.error.message, $context.error.message)
#end
{
"conversation": $util.toJson("${context.result.data}!Ref conversationTable")
"userConversations": $util.toJson("${context.result.data}!Ref userConversationsTable")
}
答案 0 :(得分:0)
After reading the CloudFormation documentation on intrinsic functions, I was able to achieve my goal using the Sub and Join functions.
In the RequestMapping template, I use Fn::Sub to set two VTL variables to the names of the tables, then I use Fn::Join to join the string with substitutions to the rest of the template string.
In the ResponseMapping template, I put placeholders in the template code for everything that needs the table names, and sub those with Fn::Sub. Then to append the table names to the context object path, I use Fn::Join to build that path entirely using the CloudFormation template, and put it in the substitution map used by Fn::Sub.
What follows is my template above with the changes
createConversationMutationResolver:
Type: "AWS::AppSync::Resolver"
Properties:
ApiId: !GetAtt chatQLApi.ApiId
TypeName: "Mutation"
FieldName: "createConversation"
DataSourceName: !GetAtt conversationsTableDataSource.Name
RequestMappingTemplate:
!Join
- ''
- - !Sub
- |
#set($conversationTable = "${conversationsTable}")
#set($userConversationTable = "${userConversationsTable}")
- { conversationTable: !Ref conversationsTable, userConversationTable: !Ref userConversationsTable }
- |
{
"version" : "2018-05-29",
"operation" : "BatchPutItem",
"tables": {
"${conversationTable}" : $util.toJson($convoList),
"${userConversationTable}" : $util.toJson($users)
}
}
ResponseMappingTemplate:
!Sub
- |
#if($context.error)
$util.appendError($context.error.message, $context.error.message)
#end
{
"${conversation}": $util.toJson(${conversationContext})
"${userConversations}": $util.toJson(${userConversationContext})
}
- {
conversation: !Ref conversationsTable,
userConversations: !Ref userConversationsTable,
conversationContext: !Join [ '.', ["$context.result.data", !Ref conversationsTable]],
userConversationContext: !Join [ '.', ["$context.result.data", !Ref userConversationsTable]]
}