API GatewayとDynamoDBを連携した自己紹介ページ作成チュートリアル

![Snag_41f7e7b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/ecd343de-49fb-6558-eeca-be5029888966.png)



## 概要

API Gateway、Lambda、DynamoDBといったサーバーレスのサービスの基礎を理解するために、
これらのサービスを使った自己紹介ページを作成するチュートリアルです。
フロントエンドはVue.js+Vuetifyを使って実装しています。

### Amazon DynamoDBとは？

Amazon DynamoDB(以降DynamoDBと表記)とは、AWSが提供する完全マネージド型のNoSQLデータベースです。NoSQLデータベースとは、従来のリレーショナルデータベースとは異なり、SQLでデータの検索等が出来ない代わりに、柔軟なテーブル設計や高速なデータの書き込み等を行うことが可能なデータベースです。また、基本的にはキー・バリュー型でデータを保存します。
DynamoDBは以下のような特徴があります。

* NoSQLなので、保存するセンサーデータに対して柔軟に対応可能
* サーバーレスなので、データベースの運用の管理が不要
* キャパシティも柔軟に変更可能なので、システム設計に優しい

今回は、ユーザー情報を保存するために、DynamoDBを利用します。

### AWS Lambdaとは？

AWS Lambda(以降Lambdaと表記)は、AWSが提供するサーバーレスでソースコードを実行できるサービスです。
ソースコード内からAWSの他のサービスを利用可能なため、Lambdaは非常に自由度の高いサービスになります。
Lambdaには以下のような特徴があります。

* サーバ管理が不要
* 実行時間のみの課金

今回は、DynamoDBに対してデータの取得、更新を行うためにLambdaを使用します。

### Amazon API Gatewayとは？

Amazon API Gateway(以降API Gatewayと表記)は、完全マネージド型のRestful APIを作成、保守出来るサービスです。API Gatewayを利用することによって、インターネット用のエンドポイントの作成が簡単に行えるので、そのエンドポイントに対して、HTTP GET/POSTといったリクエストを投げることが可能になります。また、API GatewayとLambdaを組み合わせることで、様々なサービスとの連携が可能になります。API Gatewayは以下のような特徴があります。

* サーバー管理が不要
* APIエンドポイントに対して認証をかけることが可能
* パフォーマンス、エラー、レイテンシなどのモニタリングが可能

今回、API Gatewayはブラウザからデータ取得のリクエストを受けつけるエンドポイントとして利用しています。

### Vue.js、Vuetifyとは？

Vue.jsとは、フロントエンドアプリケーションを作成するためのフレームワークです。
Vue.jsを使うと、非常に低いコストでフロントエンドアプリケーションを開発することが可能です。
Vuetifyは、Vue.jsをベースに作られたマテリアルデザインをより簡単につくることが出来るフレームワークです。
自分でCSSなどでスタイルを作ることなく、用意されたクラスと付与するだけで、綺麗なページを作ることが出来ます。

## はじめましょう

### 前提条件

* Node.js12系がインストール、設定済み
* yarnがインストール済み
* Gitが使える環境
* AWSアカウント、管理者権限の保有

### サンプルリポジトリの動作確認

```shell

$ git clone https://github.com/papi-tokei/self-introduction-tutorial-v3.git
$ cd self-introduction-tutorial-v3/frontend
$ yarn install
$ yarn serve
```

ブラウザに「`http://localhost:3000/`」を入力して、サンプルの自己紹介ページが表示されることを確認して下さい。


## DynamoDBテーブルの作成

下記内容で、テーブルを作成して下さい。
※必ず東京リージョンで実施して下さい

「デフォルト設定の使用」のチェックを外す

| 設定項目      |       設定内容 |
|:-----------------|:------------------|
| テーブル名         |  self_introduction_tutorial      |   
| パーティションキー     |  id           |  
| Auto Scale       |   Read/Writeともに無し        |  
| 読み込みキャパシティユニット       |            1 |  
| 書き込みキャパシティユニット            |             1 |  


「self_introduction_tutorial」テーブルを選択し、「項目」>「項目を作成」をクリック

| 設定項目      |       設定内容 |
|:-----------------|:------------------|
| id (string)       |  1    |   
| hobby-list(List)   |  内容は任意、stringの配列として作成 |  
| like(string)       |   内容は任意     |
| name(string)       |   内容は任意     |  
| skill(string)       |   内容は任意     |  
| comment(string)  | 内容は任意  |

![Snag_1a05d6a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/609a8e96-aaaf-8fe8-30ee-54a854d47863.png)



## Lambdaの作成

Lambda関数を作る前に、ロールの作成を行います。

1. IAMの画面から、「ロール」>「ロールの作成」をクリック
2. 信頼されたエンティティの種類を選択：AWSサービス、このロールを使用するサービス：Lambdaを選択
3. 右下の「次のステップ：アクセス権限」をクリック
4. 「ポリシーの作成」をクリック
5. 「JSON」タブを選択し、下記のJSONで上書きする

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        },
        {
            "Action": [
                "dynamodb:PutItem",
                "dynamodb:Query"
            ],
            "Effect": "Allow",
            "Resource": [
                "arn:aws:dynamodb:ap-northeast-1:*:table/self_introduction_tutorial"
            ]
        }
    ]
}
```

6.　右下の「ポリシーの確認」をクリック
7.　ポリシーの名前に「self-introduction-tutorial-lambda-policy」と入力し、右下の「ポリシーの作成」をクリックする
8.　ロールの作成画面に戻り、右上の更新マークをクリック
9.　検索ボックスに「self」を入力し、先程作成したポリシーを選択
10.　右下の「次のステップ：タグ」を選択
11.　右下の「次のステップ：確認」を選択
12.　ロール名に「SelfIntroductionTutorialLambdaRole」と入力し、右下の「ロールの作成」をクリック

続いて、Lambda関数の作成を行います。
下記項目に沿って関数を作成して下さい。

| 設定項目      |       設定内容 |
|:-----------------|:------------------|
| 関数のテンプレート         |  一から作成     |   
| 関数名     |  selfIntroductionTutorial   |  
| ランタイム       |   Python 3.8        |  
| 実行ロール       |    既存のロールを使用する  |  
| 既存のロール            |   SelfIntroductionTutorialLambdaRole |  

Lambda関数内のソースコードはクローンしたリポジトリ内の、「backend/lambda/index.py」をコピー・ペーストして下さい。
以下のように9行目をコメントアウトしてください。

```py
import json
import os
import pprint

import boto3
from boto3.dynamodb.conditions import Key

USER_TABLE_NAME = "self_introduction_tutorial"
# USER_TABLE_NAME = os.environ['TABLE_NAME'] ←この行をコメントアウトする
dynamodb = boto3.resource('dynamodb')

def handler(event, context):
```

「Deploy」を忘れずにクリックして下さい。


「ランタイム設定」の編集をクリックします

![Snag_377064af.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/fd5171b8-9821-3195-e75d-453b9cb1aaff.png)

「ハンドラ」を「lambda_function.handler」に変更して、「保存」をクリックします。

![Snag_3770fcb9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/ac00e507-2fac-f9cd-31d8-075cd4d01945.png)


## API Gatewayの作成

「今すぐ始める」か「APIの作成」をクリックして、「REST API」の「構築」ボタンをクリックし、下記の様に設定後、「APIの作成」をクリックして下さい。

| 設定項目      |       設定内容 |
|:-----------------|:------------------|
| プロトコルを選択する         |  REST     |   
| 新しいAPIの作成     |  新しいAPI |  
| API名       |   Self Introduction Tutorial       |  
| 説明       |    自己紹介チュートリアル用API  |  
| エンドポイントタイプ  |   リージョン |  

<img width="1432" alt="API_Gateway.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/a67a7b19-ba0e-f219-4a38-1eb762474878.png">

「アクション」>「リソースの作成」をクリックして下さい。
新しい子リソースの欄に以下に沿って入力、右下の「リソースの作成」をクリックして下さい。

| 設定項目      |       設定内容 |
|:-----------------|:------------------|
| リソース名         |  User Data     |   
| リソースパス     |  user-data |  
| API Gateway CORSを有効にする | チェックする |

<img width="1424" alt="API_Gateway-2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/2a1f02d1-b048-f64d-9bff-419bd3d8c244.png">

「user-data」をクリックして、「アクション」>「メソッドの作成」をクリックして下さい。

<img width="833" alt="API_Gateway_2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/1ebfe219-04d0-9ec2-f959-e21e28c01ed9.png">

「POST」を選択し、右のチェックマークをクリックして下さい。

<img width="901" alt="API_Gateway_3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/d65d2894-9d79-208b-36d3-bca144fb24c4.png">

以下に沿って入力、右下の「保存」をクリックして下さい。

| 設定項目      |       設定内容 |
|:-----------------|:------------------|
| 統合タイプ        |  Lambda関数     |   
| Lambda プロキシ統合の使用 | チェックする |
| Lambdaリージョン     |  ap-northeast-1 |  
| Lambda関数 | selfIntroductionTutorial  |

![Snag_1ac2316.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/18f686cc-9f54-ced0-5314-adade525579d.png)


「Lambda関数に権限を追加する」というポップアップが表示されるはずですので、右下の「OK」をクリックして下さい。

「アクション」>「APIのデプロイ」をクリックして下さい。

<img width="831" alt="API_Gateway_7-2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/dd1aff32-20e8-3afd-5994-11ab4de82d30.png">


「APIのデプロイ」の項目を、下記に沿って入力、右下の「デプロイ」をクリックして下さい。

| 設定項目      |       設定内容 |
|:-----------------|:------------------|
| デプロイされるステージ      |  [新しいステージ]    |   
| ステージ名     |  prod |  

<img width="596" alt="API_Gateway.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/c2901574-ed5d-224c-1211-0499671629fe.png">

Prodステージエディターの「URLの呼び出し」のhttps://から.execute-apiまでの部分をコピーして下さい。
コピーした内容を「index.vue」の110行目のXXXXXXXXの部分に貼り付けて下さい。

```javascript:self-introduction-tutorial-v3/frontend/src/components/SelfIntroductionMain.vue
// TODO: エンドポイントを修正する
const URL =
  'https://xxxx.execute-api.ap-northeast-1.amazonaws.com/prod/user-data'
```

<img width="1261" alt="API_Gateway.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/66106b78-f523-bb82-0d2b-fc8126844bc7.png">

ソースコードを修正後、保存して下さい。

### 動作確認

自己紹介画面(`http://localhost:3000/`)を画面リロードして、表示されている内容が、DynamoDBに格納した内容に変更されていることを確認して下さい。
また、下側にある更新ボタンをクリックして、編集画面を表示させて、内容を変更後、右下の「SAVE」をクリックして下さい。

![Snag_1b00c7e.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/2cd9fb2c-e8ce-28a8-87ad-1cee7d948fb4.png)

![Snag_1b1fbca.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192873/54f20866-d8dc-5b85-fba3-6fdbdf24b23f.png)



DynamoDBのレコードを確認して、内容が変更されていることを確認して下さい。

## 最後に

今回作成したAPIは認証などをかけていない、非常に危険なAPIとなっておりますので、チュートリアル実施後、必ず削除をお願いします。
また、今回作成したDynamoDBのテーブル、Lambda関数、ロール、ポリシーも不要であれば削除するようにお願いします。

駆け足ではありましたが、サーバーレスアプリケーションの雰囲気を掴んで頂ければ幸いです。
ソースコードの詳細な説明は行っておりませんので、クローンしたリポジトリ内のコードや、Lambda関数のコードを自分なりに変更して頂き、理解を深めて頂ければと思います。

### 参考リンク

* [Vue.js](https://jp.vuejs.org/index.html)
* [Vuetify](https://vuetifyjs.com/ja/getting-started/quick-start)
* [Amazon DynamoDB](https://aws.amazon.com/jp/dynamodb/)
* [Amazon API Gateway](https://aws.amazon.com/jp/api-gateway/)
* [AWS Lambda](https://aws.amazon.com/jp/lambda/)
* [boto3 reference](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/index.html)