3
votes

When creating resources in AWS CloudFormation from a yml (or json) template, is it possible to iterated over an array to keep the template brief and readable. For example, I have an Appsync project where I have to create a bunch of almost identical resolvers of AWS type "AWS::AppSync::Resolver". In the YML template used that I use with Cloud Formation, 1 such resource might look like this

Resource:
 GraphQlAddPostsResolver:
      Type: "AWS::AppSync::Resolver"
      DependsOn: GraphQlSchema
      Properties:
        ApiId:
          Fn::GetAtt: [GraphQlApi, ApiId]
        TypeName: Mutation #<---
        FieldName: addPost #<----
        DataSourceName:
          Fn::GetAtt: [GraphQlLambdaDataSource, Name]
        RequestMappingTemplate: |
          {
              "version" : "2017-02-28",
              "operation": "Invoke",
              "payload": {
                  "field": "addPost", #<---
                  "context": $util.toJson($context)
              }
          }
        ResponseMappingTemplate: |
          $util.toJson($context.result)

I might have a dozen or more of these resolvers and the only difference would be where I indicated with <----. Is there any way to iterated over an array of values, say

- Field: addPost
  Type: Mutation
- Field: allPosts
  Type: Query
- Field: getPost
  Type: Query
## etc...
2

2 Answers

7
votes

This is not possible in AWS CloudFormation. You can solve your problem with nested stacks. Use AWS::CloudFormation::Stack resources.

  FirstResolver:
    Type: AWS::CloudFormation::Stack
    DependsOn: GraphQlSchema
    Properties:
      TemplateURL: ./app-sync-resolver.yml
      Parameters:
        ApiId: !GetAtt GraphQlApi.ApiId
        DataSourceName: !GetAtt GraphQlLambdaDataSource.Name
        Field: addPost
        Type: Mutation

  SecondResolver:
    Type: AWS::CloudFormation::Stack
    DependsOn: GraphQlSchema
    Properties:
      TemplateURL: ./app-sync-resolver.yml
      Parameters:
        ApiId: !GetAtt GraphQlApi.ApiId
        DataSourceName: !GetAtt GraphQlLambdaDataSource.Name
        Field: allPosts
        Type: Query

app-sync-resolver.yml looks like this (not tested!)

AWSTemplateFormatVersion: 2010-09-09
Parameters:
  ApiId:
    Type: String
  DataSourceName:
    Type: String
  Type:
    Type: String
  Field:
    Type: String
Resource:
 GraphQLResolver:
      Type: AWS::AppSync::Resolver
      Properties:
        ApiId: !Ref ApiId
        TypeName: !Ref Type
        FieldName: !Ref Field
        DataSourceName: !Ref DataSourceName
        RequestMappingTemplate: |
          {
              "version" : "2017-02-28",
              "operation": "Invoke",
              "payload": {
                  "field": "${Field}",
                  "context": $util.toJson($context)
              }
          }
        ResponseMappingTemplate: |
          $util.toJson($context.result)
2
votes

No you can't. Cloudformation is a great tool but it has its limitations.

You may want to take a look into Jinja or Troposphere (python).