【AWS CDK入門】AWS CDKをゼロから始めて、API Gateway+Lambda+DynamoDBのリソース群をパッと作る


AWS CDKの入門として、「AWS CDKをゼロから始めて、API Gateway+Lambda+DynamoDBのリソース群をパッと作るまでの流れ」をまとめました。
手順通り実行すれば1時間ほどで試せるハンズオンになっているので、試してみてください。

## AWS CDK(Cloud Development Kit)とは？
AWSのリソース群を、より簡単に定義し作成できるフレームワークです。

## AWS CDKのメリット
AWS CDKのメリットは、入門的な観点では特に、以下2点が挙げられます。

- IDE(統合開発環境)の補完機能が使える
- 少ない記述量で、必要なリソース群を生成できる

今までは、リソースの生成・管理はCloudFormationのテンプレートファイルをJSONかYAMLの形式で全て自分で記述する必要がありました。
CDKでは、TypeScriptやPythonなどのプログラミング言語でリソースを定義するので、アプリケーションのコーディングと同様にIDEで補完機能を使いながら記述することができます。
また、リソースの定義も大部分をデフォルト値で設定できるため、多くの定義を省略することができます。そのため、記述量を少なく済ませることができます。

## ハンズオンをやってみよう
以降は、AWS CDKを体感するためのハンズオンの手順です！
手順に沿っていくと、以下の構成のAPI Gateway+Lambda+DynamoDBを作成できます。
<img width="714" alt="スクリーンショット 2020-02-20 21.52.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458187/5738b4e5-6a70-0b9c-cc13-3ea772e7aba7.png">

この構成のためにCloudFormationでは以下のようなリソース群を生成します。
![new-designer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458187/363aece7-7206-352b-b1d5-3062741fabea.png)


### 環境
OS: macOS Mojave 10.14.6
CDK CLI: 1.25.0
TypeScript: 3.7.3
Node: 10.17.0


### インストール

AWS CDKを利用するために、コマンドラインツールをインストールします。

```
$ npm install -g aws-cdk
```
インストールされているか確認するために、バージョン確認をします。

```
$ cdk --version
1.25.0 (build 309ac1b)
```

### プロジェクトの作成

CDKのプロジェクトを作成します。

```
$ mkdir cdk-test
$ cd cdk-test
$ cdk init app --language=typescript

//npm installなどが実行された後、以下が表示されます。

# Welcome to your CDK TypeScript project!

This is a blank project for TypeScript development with CDK.

The `cdk.json` file tells the CDK Toolkit how to execute your app.

## Useful commands

 * `npm run build`   compile typescript to js
 * `npm run watch`   watch for changes and compile
 * `npm run test`    perform the jest unit tests
 * `cdk deploy`      deploy this stack to your default AWS account/region
 * `cdk diff`        compare deployed stack with current state
 * `cdk synth`       emits the synthesized CloudFormation template
```
ここまで実行すると、プロジェクト内に以下のような構造が出来上がります。（1階層のみ表示しています。）

```
$ tree -L 1
.
├── README.md
├── bin
├── cdk.json
├── jest.config.js
├── lib
├── node_modules
├── package-lock.json
├── package.json
├── test
└── tsconfig.json
```
CDKで生成したいリソースは基本的に`lib`フォルダの中にある`cdk-test-stack.ts`にコードを書いて定義していくことになります。

### 必要なリソースのライブラリのインストール
生成したいリソースに応じて、使用するライブラリをインストールします。
今回は、Lambda、DynamoDB、API Gateway、IAMが必要になるので、それぞれインストールします。

```
$ npm install @aws-cdk/aws-lambda @aws-cdk/aws-dynamodb @aws-cdk/aws-apigateway @aws-cdk/aws-iam
```
### コード
生成したいリソースを`cdk-test-stack.ts`に定義していきます。
ちなみにプロジェクトを作成した初期状態では`cdk-test-stack.ts`は以下のようになっていますが、
コメントが書いてあるところにコードを追記することで、生成するリソースを定義することができます。

```cdk-test-stack.ts
import * as cdk from '@aws-cdk/core';
// ここに使用するライブラリを追記する

export class CdkTestStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    // The code that defines your stack goes here
    // ここに生成するリソースを定義する
  }
}
```
<details>
 <summary>今回は以下のように定義します。（クリックして表示） </summary>
<div>

```cdk-test-stack.ts
import * as cdk from '@aws-cdk/core'
// ここに使用するライブラリを追記する
import * as lambda from '@aws-cdk/aws-lambda'
import * as apigateway from '@aws-cdk/aws-apigateway'
import * as dynamodb from '@aws-cdk/aws-dynamodb'
import * as iam from '@aws-cdk/aws-iam'

export class CdkTestStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // The code that defines your stack goes here
    // ここに生成するリソースを定義する
    cdk.Tag.add(this, 'use-case', 'workshop')

    const tableName = 'cdk-test-table'

    // Lambdaの定義
    const cdkTestFunction = new lambda.Function(this, 'cdk-test-function', {
      // 必須の項目
      runtime: lambda.Runtime.NODEJS_12_X,
      handler: 'index.handler',
      code: lambda.Code.asset('lambda'),
      // オプション項目
      functionName: 'cdk-test-function',
      environment:{
        'TABLE_NAME': tableName
      }
    })

    // API Gatewayの定義
    const cdkTestApi = new apigateway.RestApi(this, 'cdk-test-api', {
      // オプション項目
      restApiName: 'cdk-test-api',
      deployOptions: {
        stageName: 'test'
      }
    })

    // DynamoDBの定義
    const cdkTestTable = new dynamodb.Table(this, 'cdk-test-table', {
      // 必須の項目
      partitionKey: { name: 'user_id', type: dynamodb.AttributeType.NUMBER },
      // オプション項目
      sortKey: { name: 'created_at', type: dynamodb.AttributeType.STRING },
      tableName: tableName
    })

    //Lambda→DynamoDBのアクセスポリシーの定義
    cdkTestFunction.addToRolePolicy(new iam.PolicyStatement({
      resources: [cdkTestTable.tableArn],
      actions: [
        'dynamodb:PutItem'
      ]
    }
    ))

    // API gateway→Lambdaの接続定義
    const integration = new apigateway.LambdaIntegration(cdkTestFunction)
    cdkTestApi.root.addMethod('POST', integration)
  }
}

```
</div>

### コードの中身の説明
上記の`cdk-test-stack.ts`のコードの内容について、例を取り上げて説明します。

#### リソースの定義方法について
上記コードの中で、Lambdaの定義方法を例に、リソースの定義方法について解説します。
Lambdaの定義は[公式のリファレンス](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-construct-library.html)に沿って`lambda.Function()`を使用しています。
`lambda.Function()`は3つ目の引数に`FunctionProps`がありますが、この中がLambdaの定義になります。
`lambda.Function()`の[リファレンスページ](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-lambda.Function.html)をみると、以下のような`props`を定義できるようになっています。（一部抜粋）

<img width="749" alt="スクリーンショット 2020-02-13 15.34.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458187/b4f7abc9-f910-9277-1757-aec001bf4553.png">

この中で、定義が必須なものは「Name」列の項目で「?」がついていないもの。
この中でいうと`code`、`handler`、`runtime`の3つのみが必須です。
最低限3つの`props`を定義すればLambdaが生成できちゃうということになります！
ちなみに今回のLambdaは、必須の3項目に加えて`functionName`と`environment`を定義しています。

```cdk-test-stack.ts
    // Lambdaの定義
    const cdkTestFunction = new lambda.Function(this, 'cdk-test-function', {
      // 必須の項目
      runtime: lambda.Runtime.NODEJS_12_X,
      handler: 'index.handler',
      code: lambda.Code.asset('lambda'),
      // オプション項目
      functionName: 'cdk-test-function',
      environment:{
        "TABLE_NAME": tableName
      }
    })
```
その他のリソースについても同様に定義することで生成できます。

#### 定義の追加方法
定義したリソースは、その後`methods`を利用することで追加の定義を入れることができます。
例えばLambdaでは、以下のような`methods`を利用できます。（一部抜粋）
<img width="748" alt="スクリーンショット 2020-02-13 16.17.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/458187/6d9c6de8-6ca1-680a-5f9f-67da65ab9976.png">

今回のLambdaでは、`addToRolePolicy()`を使用して、DynamoDBへのアクセスポリシーを追加しています。

```cdk-test-stack.ts
    cdkTestFunction.addToRolePolicy(new iam.PolicyStatement({
      resources: [cdkTestTable.tableArn],
      actions: [
        'dynamodb:PutItem'
      ]
    }
    ))

```

### Lambdaの関数の作成
Lambdaの中身の関数を作成していきます。
`cdk-test-stack.ts`内でLambdaは以下のような定義を指定していましたが、それぞれの定義は、横に記述したコメントの通りとなります。

```cdk-test-stack.ts
      // 必須の項目
      runtime: lambda.Runtime.NODEJS_12_X, //LambdaはNode.js(12.X)で動作します
      handler: 'index.handler', //Lambdaは"index.~"というファイルの"handler"という関数を使用します
      code: lambda.Code.asset('lambda'), //関数が記述されているファイルは"lambda"ディレクトリに格納しています

```
上記のように定義しているので、今回Lambdaで使用する関数は、以下の手順で作成していきます。
①プロジェクト直下に`lambda`ディレクトリを作成する
②lambdaディレクトリ内に`index.js`を作成する
③`index.js`内に`handler`という関数を作成する

以下は、①~③でやったことです。
①②：まず必要なディレクトリをファイルを作成するために以下コマンドを実行します。

```
$ mkdir lambda
$ cd ./lambda
$ touch index.js
$ cd ..
```

以下のような構成になっていればOKです！

```
$ tree -L 1
.
├── README.md
├── bin
├── cdk.json
├── jest.config.js
├── lambda //この中にindex.jsがあればOK!
├── lib
├── node_modules
├── package-lock.json
├── package.json
├── test
└── tsconfig.json
```

③：handler関数を定義します。

<details>
 <summary>`index.js`には以下のようなプログラムを書きました。（クリックして表示） </summary>
<div>

```index.js
const AWS = require('aws-sdk')
const client = new AWS.DynamoDB.DocumentClient()
const tableName =  process.env.TABLE_NAME
let items = {}
const get_time = () => {
	let dt = new Date()
	dt.setTime(dt.getTime() + 32400000)

	let year  = dt.getFullYear()
	let month = dt.getMonth()+1
	let day   = dt.getDate()
	let hour  = dt.getHours()
	let min   = dt.getMinutes()
	let sec = dt.getSeconds()

	if (month < 10) {
	    month = '0' + month
	}

	if (day   < 10) {
	    day   = '0' + day
	}

	if (hour   < 10) {
	    hour  = '0' + hour
	}

	if (min   < 10) {
	    min   = '0' + min
	}
	if (sec   < 10) {
	    sec   = '0' + sec
	}

	let Date_now = year + '/' + month + '/' + day + '-' + hour + ':' + min + ':' + sec
	return Date_now
}

exports.handler = async (event) => {
	if (typeof(event.body) === 'string') {
		items = JSON.parse(event.body)
	} else {
		items = event.body
	}
	const params = {
    TableName: tableName,
    Item: {
        user_id: items.user_id,
        created_at: get_time(),
        amount: items.amount
	    }
	}
	console.log(params)
	await client.put(params).promise()

	return {
		statusCode: 200,
		body: 'Put Success: ' + JSON.stringify(items)
	}
}
```
</div>
### 生成されるCloudFormationテンプレートの確認

ここまで定義した内容で、どのようなCloudFormationテンプレートが生成されるかを確認するために、以下のコマンドを実行します。

```
$ cdk synth
```
このコマンドを実行すると、YAML形式のCloudFormationテンプレートがコマンドラインに表示されます。
同時に`cdk.out`というディレクトリが生成され、その中に`CdkTestStack.template.json`というJSON形式のCloudFormationテンプレートも生成されます。

<details>
 <summary>コマンドラインに表示されるYAML形式のテンプレートは、以下のようになりました。（クリックして展開） </summary>
<div>

```cdk-test-stack-template.yaml
Resources:
  cdktestfunctionServiceRole4CE3A73D:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
        Version: "2012-10-17"
      ManagedPolicyArns:
        - Fn::Join:
            - ""
            - - "arn:"
              - Ref: AWS::Partition
              - :iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Tags:
        - Key: use-case
          Value: workshop
    Metadata:
      aws:cdk:path: CdkTestStack/cdk-test-function/ServiceRole/Resource
  cdktestfunctionServiceRoleDefaultPolicy070552D2:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Statement:
          - Action: dynamodb:PutItem
            Effect: Allow
            Resource:
              Fn::GetAtt:
                - cdktesttableB0274F47
                - Arn
        Version: "2012-10-17"
      PolicyName: cdktestfunctionServiceRoleDefaultPolicy070552D2
      Roles:
        - Ref: cdktestfunctionServiceRole4CE3A73D
    Metadata:
      aws:cdk:path: CdkTestStack/cdk-test-function/ServiceRole/DefaultPolicy/Resource
  cdktestfunction799CDE6C:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket:
          Ref: AssetParameters008187cf4b97caf9f33bda82c0b2bf2d0cbdb4f5e4a1f8a81f97d02c6424b1d1S3Bucket612EC6C8
        S3Key:
          Fn::Join:
            - ""
            - - Fn::Select:
                  - 0
                  - Fn::Split:
                      - "||"
                      - Ref: AssetParameters008187cf4b97caf9f33bda82c0b2bf2d0cbdb4f5e4a1f8a81f97d02c6424b1d1S3VersionKeyE312B4F3
              - Fn::Select:
                  - 1
                  - Fn::Split:
                      - "||"
                      - Ref: AssetParameters008187cf4b97caf9f33bda82c0b2bf2d0cbdb4f5e4a1f8a81f97d02c6424b1d1S3VersionKeyE312B4F3
      Handler: index.handler
      Role:
        Fn::GetAtt:
          - cdktestfunctionServiceRole4CE3A73D
          - Arn
      Runtime: nodejs12.x
      Environment:
        Variables:
          TABLE_NAME: cdk-test-table
      FunctionName: cdk-test-function
      Tags:
        - Key: use-case
          Value: workshop
    DependsOn:
      - cdktestfunctionServiceRoleDefaultPolicy070552D2
      - cdktestfunctionServiceRole4CE3A73D
    Metadata:
      aws:cdk:path: CdkTestStack/cdk-test-function/Resource
      aws:asset:path: asset.008187cf4b97caf9f33bda82c0b2bf2d0cbdb4f5e4a1f8a81f97d02c6424b1d1
      aws:asset:property: Code
  cdktestapi858A14F7:
    Type: AWS::ApiGateway::RestApi
    Properties:
      Name: cdk-test-api
      Tags:
        - Key: use-case
          Value: workshop
    Metadata:
      aws:cdk:path: CdkTestStack/cdk-test-api/Resource
  cdktestapiDeploymentAB660FEA292ba9738d8401cffa10885c9e10869a:
    Type: AWS::ApiGateway::Deployment
    Properties:
      RestApiId:
        Ref: cdktestapi858A14F7
      Description: Automatically created by the RestApi construct
    DependsOn:
      - cdktestapiPOST9C619890
    Metadata:
      aws:cdk:path: CdkTestStack/cdk-test-api/Deployment/Resource
  cdktestapiDeploymentStagetest9C960D82:
    Type: AWS::ApiGateway::Stage
    Properties:
      RestApiId:
        Ref: cdktestapi858A14F7
      DeploymentId:
        Ref: cdktestapiDeploymentAB660FEA292ba9738d8401cffa10885c9e10869a
      StageName: test
      Tags:
        - Key: use-case
          Value: workshop
    Metadata:
      aws:cdk:path: CdkTestStack/cdk-test-api/DeploymentStage.test/Resource
  cdktestapiCloudWatchRoleA4E10D45:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: apigateway.amazonaws.com
        Version: "2012-10-17"
      ManagedPolicyArns:
        - Fn::Join:
            - ""
            - - "arn:"
              - Ref: AWS::Partition
              - :iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs
      Tags:
        - Key: use-case
          Value: workshop
    Metadata:
      aws:cdk:path: CdkTestStack/cdk-test-api/CloudWatchRole/Resource
  cdktestapiAccountF8B5456F:
    Type: AWS::ApiGateway::Account
    Properties:
      CloudWatchRoleArn:
        Fn::GetAtt:
          - cdktestapiCloudWatchRoleA4E10D45
          - Arn
    DependsOn:
      - cdktestapi858A14F7
    Metadata:
      aws:cdk:path: CdkTestStack/cdk-test-api/Account
  cdktestapiPOSTApiPermissionCdkTestStackcdktestapiB9D3D388POST29D4184B:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName:
        Fn::GetAtt:
          - cdktestfunction799CDE6C
          - Arn
      Principal: apigateway.amazonaws.com
      SourceArn:
        Fn::Join:
          - ""
          - - "arn:"
            - Ref: AWS::Partition
            - ":execute-api:"
            - Ref: AWS::Region
            - ":"
            - Ref: AWS::AccountId
            - ":"
            - Ref: cdktestapi858A14F7
            - /
            - Ref: cdktestapiDeploymentStagetest9C960D82
            - /POST/
    Metadata:
      aws:cdk:path: CdkTestStack/cdk-test-api/Default/POST/ApiPermission.CdkTestStackcdktestapiB9D3D388.POST..
  cdktestapiPOSTApiPermissionTestCdkTestStackcdktestapiB9D3D388POSTAD710B52:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName:
        Fn::GetAtt:
          - cdktestfunction799CDE6C
          - Arn
      Principal: apigateway.amazonaws.com
      SourceArn:
        Fn::Join:
          - ""
          - - "arn:"
            - Ref: AWS::Partition
            - ":execute-api:"
            - Ref: AWS::Region
            - ":"
            - Ref: AWS::AccountId
            - ":"
            - Ref: cdktestapi858A14F7
            - /test-invoke-stage/POST/
    Metadata:
      aws:cdk:path: CdkTestStack/cdk-test-api/Default/POST/ApiPermission.Test.CdkTestStackcdktestapiB9D3D388.POST..
  cdktestapiPOST9C619890:
    Type: AWS::ApiGateway::Method
    Properties:
      HttpMethod: POST
      ResourceId:
        Fn::GetAtt:
          - cdktestapi858A14F7
          - RootResourceId
      RestApiId:
        Ref: cdktestapi858A14F7
      AuthorizationType: NONE
      Integration:
        IntegrationHttpMethod: POST
        Type: AWS_PROXY
        Uri:
          Fn::Join:
            - ""
            - - "arn:"
              - Ref: AWS::Partition
              - ":apigateway:"
              - Ref: AWS::Region
              - :lambda:path/2015-03-31/functions/
              - Fn::GetAtt:
                  - cdktestfunction799CDE6C
                  - Arn
              - /invocations
    Metadata:
      aws:cdk:path: CdkTestStack/cdk-test-api/Default/POST/Resource
  cdktesttableB0274F47:
    Type: AWS::DynamoDB::Table
    Properties:
      KeySchema:
        - AttributeName: user_id
          KeyType: HASH
        - AttributeName: created_at
          KeyType: RANGE
      AttributeDefinitions:
        - AttributeName: user_id
          AttributeType: "N"
        - AttributeName: created_at
          AttributeType: S
      ProvisionedThroughput:
        ReadCapacityUnits: 5
        WriteCapacityUnits: 5
      TableName: cdk-test-table
      Tags:
        - Key: use-case
          Value: workshop
    UpdateReplacePolicy: Retain
    DeletionPolicy: Retain
    Metadata:
      aws:cdk:path: CdkTestStack/cdk-test-table/Resource
  CDKMetadata:
    Type: AWS::CDK::Metadata
    Properties:
      Modules: aws-cdk=1.25.0,@aws-cdk/assets=1.23.0,@aws-cdk/aws-apigateway=1.23.0,@aws-cdk/aws-applicationautoscaling=1.23.0,@aws-cdk/aws-autoscaling-common=1.23.0,@aws-cdk/aws-cloudwatch=1.23.0,@aws-cdk/aws-dynamodb=1.23.0,@aws-cdk/aws-ec2=1.23.0,@aws-cdk/aws-events=1.23.0,@aws-cdk/aws-iam=1.23.0,@aws-cdk/aws-kms=1.23.0,@aws-cdk/aws-lambda=1.23.0,@aws-cdk/aws-logs=1.23.0,@aws-cdk/aws-s3=1.23.0,@aws-cdk/aws-s3-assets=1.23.0,@aws-cdk/aws-sqs=1.23.0,@aws-cdk/aws-ssm=1.23.0,@aws-cdk/core=1.23.0,@aws-cdk/cx-api=1.23.0,@aws-cdk/region-info=1.23.0,jsii-runtime=node.js/v10.17.0
    Condition: CDKMetadataAvailable
Parameters:
  AssetParameters008187cf4b97caf9f33bda82c0b2bf2d0cbdb4f5e4a1f8a81f97d02c6424b1d1S3Bucket612EC6C8:
    Type: String
    Description: S3 bucket for asset "008187cf4b97caf9f33bda82c0b2bf2d0cbdb4f5e4a1f8a81f97d02c6424b1d1"
  AssetParameters008187cf4b97caf9f33bda82c0b2bf2d0cbdb4f5e4a1f8a81f97d02c6424b1d1S3VersionKeyE312B4F3:
    Type: String
    Description: S3 key for asset version "008187cf4b97caf9f33bda82c0b2bf2d0cbdb4f5e4a1f8a81f97d02c6424b1d1"
  AssetParameters008187cf4b97caf9f33bda82c0b2bf2d0cbdb4f5e4a1f8a81f97d02c6424b1d1ArtifactHash93D2A514:
    Type: String
    Description: Artifact hash for asset "008187cf4b97caf9f33bda82c0b2bf2d0cbdb4f5e4a1f8a81f97d02c6424b1d1"
Outputs:
  cdktestapiEndpoint867D566B:
    Value:
      Fn::Join:
        - ""
        - - https://
          - Ref: cdktestapi858A14F7
          - .execute-api.
          - Ref: AWS::Region
          - "."
          - Ref: AWS::URLSuffix
          - /
          - Ref: cdktestapiDeploymentStagetest9C960D82
          - /
Conditions:
  CDKMetadataAvailable:
    Fn::Or:
      - Fn::Or:
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-east-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-northeast-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-northeast-2
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-south-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-southeast-1
          - Fn::Equals:
              - Ref: AWS::Region
              - ap-southeast-2
          - Fn::Equals:
              - Ref: AWS::Region
              - ca-central-1
          - Fn::Equals:
              - Ref: AWS::Region
              - cn-north-1
          - Fn::Equals:
              - Ref: AWS::Region
              - cn-northwest-1
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-central-1
      - Fn::Or:
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-north-1
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-west-1
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-west-2
          - Fn::Equals:
              - Ref: AWS::Region
              - eu-west-3
          - Fn::Equals:
              - Ref: AWS::Region
              - me-south-1
          - Fn::Equals:
              - Ref: AWS::Region
              - sa-east-1
          - Fn::Equals:
              - Ref: AWS::Region
              - us-east-1
          - Fn::Equals:
              - Ref: AWS::Region
              - us-east-2
          - Fn::Equals:
              - Ref: AWS::Region
              - us-west-1
          - Fn::Equals:
              - Ref: AWS::Region
              - us-west-2
```
</div>
</details>
約500行ほどあります。
この内容を約50行程度のコードで定義できるのがCDKの良いところです！

### デプロイ

いよいよAWS上にリソースを生成していきます。
以下のコマンドを実行します。

```
$ cdk deploy --profile [your profile]
// 変更点が表示される
Do you wish to deploy these changes (y/n)? //デプロイする場合は"y"を押してEnter
```

`[your profile]`にはCDKをデプロイしたいAWSのプロファイルを入れます。
そうするとリソースが生成されて、最終的に以下のような表示が出ます。

```
 ✅  CdkTestStack

Outputs:
CdkTestStack.cdktestapiEndpointXXXXXXXX = https://YYYYYYYYYY.execute-api.[region name].amazonaws.com/test/

Stack ARN:
arn:aws:cloudformation:[cdk stack's arn]
```
※XXXや、YYYや[]の中は人それぞれになります。

### 実行確認
自分のターミナルからApiのエンドポイントにPOSTリクエストをして、DynamoDBのテーブルにリクエストした内容が追加されているか確認します。

```
$ curl -X POST -d '{"user_id": 333, "amount":1000}' https://XXXXXXXXXX.execute-api.[region name].amazonaws.com/test/
Put Success: {"user_id":333,"amount":1000}
$ aws dynamodb scan --table-name cdk-test-table --profile [your profile]
//DynamoDBの中身を確認
{
    "Count": 1, 
    "Items": [
        {
            "amount": {
                "N": "1000"
            }, 
            "user_id": {
                "N": "333"
            }, 
            "created_at": {
                "S": "2020/02/20-20:57:51"
            }
        }
    ], 
    "ScannedCount": 1, 
    "ConsumedCapacity": null
}
```
上記のように中身にリクエスト内容が追加されていれば成功です！

### 削除

生成したリソース群を削除する場合は、以下のコマンドを使用します。

```
$ cdk destroy --profile [your profile]
Are you sure you want to delete: CdkTestStack (y/n)? //削除する場合は"y"を押してEnter
```

S3やDynamoDB等このコマンドでは削除されないリソースがあります。こういったリソースは、同じリソース名を指定してデプロイしようとすると、リソース名重複のエラーが出てデプロイできないので注意です。

### その他のコマンド：変更の確認

CDKのコードを変更し、生成するリソースの差分をみるときは、以下のコマンドを使います。

```
$ cdk diff --profile [your profile]
```

## おわりに
CDKの入門的な説明から、ハンズオンの内容までをまとめました。
初めてCDKに触れる方は、CDKで簡単にリソースが生成できることが体感できるかと思います。

便利に使いこなして、素敵なAWSライフを過ごしましょう！
それでは！



## 参考
https://dev.classmethod.jp/server-side/serverless/aws-cdk-lambda/
https://qiita.com/yhsmt/items/80916a13b3d7ae8adc7f