是否可以在AppSync解析器中引用CloudFormation资源名称?

时间:2018-09-21 18:20:15

标签: amazon-web-services amazon-cloudformation aws-appsync

我在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")
    }

1 个答案:

答案 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]]
        }