0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

AWS AppSyncでAPIを作ってみたAdvent Calendar 2022

Day 7

AppSyncのCloudFormation化

Last updated at Posted at 2022-12-06

概要

アドベントカレンダー の1日目から5日目で作成したAppSyncとDynamoDBをCloudFormationで自動作成する方法を紹介します。

YMLファイルの作成

cfn.yml
  Resources:
    DynamoDBRadioTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: Radio
        AttributeDefinitions:
        - AttributeName: id
          AttributeType: S
        KeySchema:
        - AttributeName: id
          KeyType: HASH
        BillingMode: PAY_PER_REQUEST
    
    AppSyncDynamoDBRole:
      Type: AWS::IAM::Role
      Properties:
        RoleName: AppSyncDynamoDBRole
        AssumeRolePolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action:
            - sts:AssumeRole
            Principal:
              Service:
              - appsync.amazonaws.com
        Path: '/'
        Policies:
        - PolicyName: AppSyncDynamoDBPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
              - dynamodb:PutItem
              - dynamodb:DeleteItem
              - dynamodb:GetItem
              - dynamodb:Scan
              - dynamodb:Query
              - dynamodb:UpdateItem
              Resource: '*'
    
    ApiCache:
      Type: AWS::AppSync::ApiCache
      Properties:
        ApiCachingBehavior: PER_RESOLVER_CACHING
        ApiId: !GetAtt GraphQLApi.ApiId
        Ttl: 60
        Type: SMALL
    
    DataSourceRadio:
      Type: AWS::AppSync::DataSource
      Properties:
        ApiId: !GetAtt GraphQLApi.ApiId
        Name: Radio
        Type: AMAZON_DYNAMODB
        ServiceRoleArn: !GetAtt AppSyncDynamoDBRole.Arn
        DynamoDBConfig:
          AwsRegion: ap-northeast-1
          TableName: !Ref DynamoDBRadioTable
    
    GraphQLApi:
      Type: AWS::AppSync::GraphQLApi
      Properties:
        AuthenticationType: AWS_IAM
        Name: Radio App
  
    GraphQLSchema:
      Type: AWS::AppSync::GraphQLSchema
      Properties:
        ApiId: !GetAtt GraphQLApi.ApiId
        Definition: |
          input CreateRadioInput {
            id: ID!
            program_name: String
            cast: [String!]
            weekday: Int
            time: String
            favorite: Boolean
          }
  
          input DeleteRadioInput {
            id: ID!
          }
  
          type Mutation {
            createRadio(input: CreateRadioInput!): Radio
            updateRadio(input: UpdateRadioInput!): Radio
            deleteRadio(input: DeleteRadioInput!): Radio
          }
  
          type Query {
            getRadio(id: ID!): Radio
            listRadio(filter: TableRadioFilterInput, limit: Int, nextToken: String): RadioConnection
          }
  
          type Radio {
            id: ID!
            program_name: String
            cast: [String!]
            weekday: Int
            time: String
            favorite: Boolean
          }
  
          type RadioConnection {
            items: [Radio]
            nextToken: String
          }
  
          input TableBooleanFilterInput {
            ne: Boolean
            eq: Boolean
          }
  
          input TableIntFilterInput {
            ne: Int
            eq: Int
            le: Int
            lt: Int
            ge: Int
            gt: Int
            contains: Int
            notContains: Int
            between: [Int]
          }
  
          input TableRadioFilterInput {
            day: TableIntFilterInput
            time: TableStringFilterInput
            favorite: TableBooleanFilterInput
          }
  
          input TableStringFilterInput {
            ne: String
            eq: String
            le: String
            lt: String
            ge: String
            gt: String
            contains: String
            notContains: String
            between: [String]
            beginsWith: String
          }
  
          input UpdateRadioInput {
            id: ID!
            program_name: String
            cast: [String!]
            day: Int
            time: String
            favorite: Boolean
          }
  
    ResolverCreateRadio:
      Type: AWS::AppSync::Resolver
      Properties:
        ApiId: !GetAtt GraphQLApi.ApiId
        DataSourceName: !GetAtt DataSourceRadio.Name
        TypeName: "Mutation"
        FieldName: "createRadio"
        Kind: UNIT
        RequestMappingTemplate: |
          {
            "version": "2017-02-28",
            "operation": "PutItem",
            "key": {
                "id": $util.dynamodb.toDynamoDBJson($ctx.args.input.id)
            },
            "attributeValues": $util.dynamodb.toMapValuesJson($ctx.args.input),
            "condition": {
                "expression": "attribute_not_exists(#id)",
                "expressionNames": {
                "#id": "id"
                }
            }
          }
        ResponseMappingTemplate: |
          $util.toJson($ctx.result)
    
    ResolverUpdateRadio:
      Type: AWS::AppSync::Resolver
      Properties:
        ApiId: !GetAtt GraphQLApi.ApiId
        DataSourceName: !GetAtt DataSourceRadio.Name
        TypeName: "Mutation"
        FieldName: "updateRadio"
        Kind: UNIT
        RequestMappingTemplate: |
          {
            "version": "2017-02-28",
            "operation": "UpdateItem",
            "key": {
              "id": $util.dynamodb.toDynamoDBJson($ctx.args.input.id),
            },
  
            ## Set up some space to keep track of things we're updating **
            #set( $expNames  = {} )
            #set( $expValues = {} )
            #set( $expSet = {} )
            #set( $expAdd = {} )
            #set( $expRemove = [] )
  
            ## Iterate through each argument, skipping keys **
            #foreach( $entry in $util.map.copyAndRemoveAllKeys($ctx.args.input, ["id"]).entrySet() )
              #if( $util.isNull($entry.value) )
                ## If the argument is set to "null", then remove that attribute from the item in DynamoDB **
  
                #set( $discard = ${expRemove.add("#${entry.key}")} )
                $!{expNames.put("#${entry.key}", "${entry.key}")}
              #else
                ## Otherwise set (or update) the attribute on the item in DynamoDB **
  
                $!{expSet.put("#${entry.key}", ":${entry.key}")}
                $!{expNames.put("#${entry.key}", "${entry.key}")}
                $!{expValues.put(":${entry.key}", $util.dynamodb.toDynamoDB($entry.value))}
              #end
            #end
  
            ## Start building the update expression, starting with attributes we're going to SET **
            #set( $expression = "" )
            #if( !${expSet.isEmpty()} )
              #set( $expression = "SET" )
              #foreach( $entry in $expSet.entrySet() )
                #set( $expression = "${expression} ${entry.key} = ${entry.value}" )
                #if ( $foreach.hasNext )
                  #set( $expression = "${expression}," )
                #end
              #end
            #end
  
            ## Continue building the update expression, adding attributes we're going to ADD **
            #if( !${expAdd.isEmpty()} )
              #set( $expression = "${expression} ADD" )
              #foreach( $entry in $expAdd.entrySet() )
                #set( $expression = "${expression} ${entry.key} ${entry.value}" )
                #if ( $foreach.hasNext )
                  #set( $expression = "${expression}," )
                #end
              #end
            #end
  
            ## Continue building the update expression, adding attributes we're going to REMOVE **
            #if( !${expRemove.isEmpty()} )
              #set( $expression = "${expression} REMOVE" )
  
              #foreach( $entry in $expRemove )
                #set( $expression = "${expression} ${entry}" )
                #if ( $foreach.hasNext )
                  #set( $expression = "${expression}," )
                #end
              #end
            #end
  
            ## Finally, write the update expression into the document, along with any expressionNames and expressionValues **
            "update": {
              "expression": "${expression}",
              #if( !${expNames.isEmpty()} )
                "expressionNames": $utils.toJson($expNames),
              #end
              #if( !${expValues.isEmpty()} )
                "expressionValues": $utils.toJson($expValues),
              #end
            },
  
            "condition": {
              "expression": "attribute_exists(#id)",
              "expressionNames": {
                "#id": "id",
              },
            }
          }
        ResponseMappingTemplate: |
          $util.toJson($ctx.result)
  
    ResolverDeleteRadio:
      Type: AWS::AppSync::Resolver
      Properties:
        ApiId: !GetAtt GraphQLApi.ApiId
        DataSourceName: !GetAtt DataSourceRadio.Name
        TypeName: "Mutation"
        FieldName: "deleteRadio"
        Kind: UNIT
        RequestMappingTemplate: |
          {
            "version": "2017-02-28",
            "operation": "DeleteItem",
            "key": {
            "id": $util.dynamodb.toDynamoDBJson($ctx.args.input.id)
            }
          }
        ResponseMappingTemplate: |
          $util.toJson($ctx.result)
  
    ResolverGetRadio:
      Type: AWS::AppSync::Resolver
      Properties:
        ApiId: !GetAtt GraphQLApi.ApiId
        DataSourceName: !GetAtt DataSourceRadio.Name
        TypeName: "Query"
        FieldName: "getRadio"
        Kind: UNIT
        RequestMappingTemplate: |
          {
            "version": "2017-02-28",
            "operation": "GetItem",
            "key": {
            "id": $util.dynamodb.toDynamoDBJson($ctx.args.id)
            }
          }
        ResponseMappingTemplate: |
          $util.toJson($ctx.result)

    ResolverListRadio:
      Type: AWS::AppSync::Resolver
      Properties:
        ApiId: !GetAtt GraphQLApi.ApiId
        DataSourceName: !GetAtt DataSourceRadio.Name
        TypeName: "Query"
        FieldName: "listRadio"
        Kind: UNIT
        RequestMappingTemplate: |
          {
            "version": "2017-02-28",
            "operation": "Scan",
            "filter": #if($context.args.filter) $util.transform.toDynamoDBFilterExpression($ctx.args.filter) #else null #end,
            "limit": $util.defaultIfNull($ctx.args.limit, 200),
            "nextToken": $util.toJson($util.defaultIfNullOrEmpty($ctx.args.nextToken, null)),
          }
        ResponseMappingTemplate: |
          $util.toJson($ctx.result)

スタックの作成

  • CloudFormationのコンソールから[スタックの作成]を選択し、[新しいリソースを使用(標準)]を押下する。
  • ステップ1
    ステップ1
  • ステップ2
    ステップ2
  • ステップ3
    • デフォルトのまま[次へ]を選択する。
  • ステップ4
    • デフォルトのまま[送信]を押下する。
  • ステータスがCREATE_COMPLETEになれば成功です。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?