Lambda + API Gateway で REST API の作成 (おまけで SAM)

タイトルの通りです。
n番煎じとかは気にせず、知らない方にとっては役に立つかと思ったので題材これにしました。

# ざっくりと説明
詳しい説明は省略。
REST API は自分でググった方が読みやすい記事が見つかるでしょう。
各サービスについては下記をどうぞ。
結局 AWS の公式がわかりやすいです。
> [AWS Lambda](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/welcome.html)
[Amazon API Gateway](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/welcome.html)

## REST API
- URI とリソースが対応付けられる
- HTTP メソッドで通信を行う
- 実行結果は json 等のデータ及びステータスコードで返される
- 状態管理をしない

## AWS Lambda
- サーバーレスでコードが実行できるサービス
  - サーバー管理やスケーリングが要らないので楽
- リクエスト数とコードの実行時間で課金される
  - サーバー建てるよりも料金が安い
  - そもそも[無料利用枠](https://aws.amazon.com/jp/lambda/pricing/)もあるので試すだけならタダ

## Amazon API Gateway
- リクエストを受け取り EC2 や Lambda に流す
  - API 処理をまとめることができるため効率up
  - 外部通信を減らすことができるためセキュリティ的にも良い
- コール数と送信データ量とオプションのキャッシュ機能で課金される
  - そもそも[無料利用枠](https://aws.amazon.com/jp/api-gateway/pricing/)もあるのd((

# 作成
![Server-Less.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/ae347120-0cfa-26ef-e43a-6d769662943f.png)

1. [AWS Lambda](#lambda)
2. [Amazon API Gateway](#api-gateway)

## Lambda
まずは Lambda から作成していきます。
マネジメントコンソールから Lambda を選択し、関数の作成へ。
関数名の入力とランタイムの選択、ランタイムは何でもいいです。
ついでに Lambda 実行用のロールがなければ作成しておきます。
![lambda-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/e937d3ac-1dca-6664-9ca4-b1b33d347ced.png)
![lambda-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/b959b4b4-647d-f4dd-3a04-ff2af1de26f1.png)

作成できました。
デフォルトでは lambda_function.lambda_handler のコードが実行されます。
![lambda-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/ae728b08-dac6-7a96-80b5-1d721d544887.png)
![lambda-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/e08382dd-53d6-a0ab-2d05-09627e06693d.png)

今回は書き換えないので実行結果として 'Hello from Lambda!' の json が帰ってきます。

## API Gateway
続いて API Gateway の作成。
HTTP API の構築で以下を選択し、API 名を入力。
![api-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/85f1b979-7cf3-ae0d-0a67-47b2afb47083.png)

アクション、メソッドの作成から GET を作成。
![api-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/19de8293-e969-4593-39c9-39d3d701243d.png)
![api-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/3b947ef8-f258-ae16-aec2-eb7da0d4eaeb.png)

ここに http://~/ へ GET リクエストが来た時の動作を設定します。
Lambda 関数を指定し、先ほど作成した Test-Function を選択後、保存。
「Lambda プロキシの統合の使用」はチェックを入れておくと、HTTP ヘッダー等のリクエスト時の情報を Lambda に渡してくれます。
「デフォルトタイムアウトの使用」は Lambda の実行時間に制限を持たせ、エラー処理等に利用します。
![api-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/db144e3a-e492-6353-44a5-a13c4c21abf1.png)

API Gateway に Lambda 関数を呼び出す権限を与えます。
![api-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/596df9d2-810d-3dae-ec6e-1f10624538c5.png)

まだ設定しただけで公開は出来ていないので、アクションから API のデプロイを選択します。
![api-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/f3b3476f-ed25-b093-b112-e07c1b6eaad5.png)

ステージはバージョン管理等のための設定です。
今回は関係ないので適当に設定しデプロイ。
![api-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/7f210c6d-2526-d9df-02d6-eb4cc57a210d.png)

作成できました。
URL の呼び出しから API Gateway に HTTP でアクセス。
![api-8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/d0e4eebd-8350-79eb-26a0-30a3e91eea4d.png)

Lambda からの結果を確認できます。
![api-9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/aac52658-f826-b66e-2ccc-9858900bc162.png)

# 削除
それぞれのサービスを削除するだけです。
不要であれば CloudWatch Logs の Lambda のログストリームも削除しておきましょう。

# 総括
お疲れ様でした。
本当に利用する際は DB 等も追加するでしょうが、AWS のサービスを利用すれば親和性が高いため容易にできるかと思います。
サーバーの設定や管理で消耗するのとかしんどいので、この記事で「サーバーレス試してみよう」となる方がいらっしゃれば幸いです。

# おまけ
~~総括の後に書くのどうなんだ？~~
冒頭で気にしないとは言ったものの、ありふれた内容なのでおまけとして自分の好きな SAM を。

## AWS SAM
Serverless Application Model
サーバーレスアプリケーションを作成するためのオープンソースフレームワークです。
本記事で作成したものをコードで簡単に作成することができます。

> [AWS SAM](https://docs.aws.amazon.com/ja_jp/serverlessrepo/latest/devguide/using-aws-sam.html)

## 準備

環境
Windows 10

AWS CLI 1.16.296
[AWS CLI](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-install.html)

AWS SAM CLI 0.37.0
[AWS SAM CLI](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)

## 作成
手順
> [AWS SAM Tutorial](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-getting-started-hello-world.html)

適当なところで sam init でディレクトリ配下にプロジェクトを作成。

```
$ sam init
```
聞かれた通りに入力していきます。

```
Which template source would you like to use?
    1 - AWS Quick Start Templates
    2 - Custom Template Location
Choice: 1


Which runtime would you like to use?
    1 - nodejs12.x
    2 - python3.8
    3 - ruby2.5
    4 - go1.x
    5 - java11
    6 - dotnetcore2.1
    7 - nodejs10.x
    8 - nodejs8.10
    9 - nodejs6.10
    10 - python3.7
    11 - python3.6
    12 - python2.7
    13 - java8
    14 - dotnetcore2.0
    15 - dotnetcore1.0
Runtime: 10


Project name [sam-app]: ApiGateway-Lambda


Quick start templates may have been updated. Do you want to re-download the latest [Y/n]: n


AWS quick start application templates:
        1 - Hello World Example
        2 - EventBridge Hello World
        3 - EventBridge App from scratch (100+ Event Schemas)
Template selection: 1

```
下記が出力され作成完了。

```
-----------------------
Generating application:
-----------------------
Name: ApiGateway-Lambda
Runtime: python3.7
Dependency Manager: pip
Application Template: hello-world
Output Directory: .

Next steps can be found in the README file at ./Test/README.md
```
そのまま build します。

```
$ cd ApiGateway-Lambda

$ sam build
```
```
Building resource 'HelloWorldFunction'
Running PythonPipBuilder:ResolveDependencies
Running PythonPipBuilder:CopySource

Build Succeeded

Built Artifacts  : .aws-sam\build
Built Template   : .aws-sam\build\template.yaml

Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Deploy: sam deploy --guided
```
```
$ ls -la
total 24
drwxrwxr-x    2 itti     itti          4096 Dec 11 16:48 .
drwxrwxr-x    2 itti     itti          4096 Dec 11 15:40 ..
drwxrwxr-x    2 itti     itti             0 Dec 11 16:48 .aws-sam
-rw-rw-r--    1 itti     itti          3973 Dec 11 15:34 .gitignore
-rw-rw-r--    1 itti     itti          7709 Dec 11 15:34 README.md
drwxrwxr-x    2 itti     itti             0 Dec 11 15:34 events
drwxrwxr-x    2 itti     itti             0 Dec 11 15:34 hello_world
-rw-rw-r--    1 itti     itti          1682 Dec 11 15:34 template.yaml
drwxrwxr-x    2 itti     itti             0 Dec 11 15:34 tests
```
デプロイ

```
$ sam deploy --guided
```
```
Configuring SAM deploy
======================

        Looking for samconfig.toml :  Not found

        Setting default arguments for 'sam deploy'
        =========================================
        Stack Name [sam-app]: ApiGateway-Lambda
        AWS Region [us-east-1]: ap-northeast-1
        #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
        Confirm changes before deploy [y/N]: Y
        #SAM needs permission to be able to create roles to connect to the resources in your template
        Allow SAM CLI IAM role creation [Y/n]: Y
        Save arguments to samconfig.toml [Y/n]: Y

-----------
長いので省略
-----------


Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: Y


-----------
長いので省略
-----------


Successfully created/updated stack - ApiGateway-Lambda in ap-northeast-1

```

## 確認
Lambda と API Gateway が作成されています。
![sam-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/824d2b1a-3284-e06c-e391-26ec2e97339b.png)
![sam-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/1892b27e-73b0-91b8-cda8-a505d97bc3ed.png)

先程と同様に。
今回は /Prod/hello なのでそこへ
![sam-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/7559c276-0efb-334a-2008-cf8140a057aa.png)
![sam-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/cc4be505-c7c3-9bb2-af12-73d678569e7b.png)

## 変更
これは内部で CloudFormation というサービスが動いていて yaml ファイルからリソースを作成しています。
なので、sam init 時に作成された yaml を確認。
AWS::Serverless::Function は Lambda に相当します。
![sam-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/531c43ea-2fe2-7f36-7739-beb9340eba41.png)
hello_world/app.lambda_handler を呼び出していることがわかりました。
![sam-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/d5c2b0a3-6070-d897-dcfd-a3e9cd80a78a.png)
lambda_handler 内の記述を変更。
message の value を 'hoge hoge' にします。
![sam-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/e07e4588-d9bc-d17a-3b8a-471af5f13b44.png)

もう一度 build から。

```
$ sam build
```
```
sam buildBuilding resource 'HelloWorldFunction'
Running PythonPipBuilder:ResolveDependencies
Running PythonPipBuilder:CopySource

Build Succeeded

Built Artifacts  : .aws-sam\build
Built Template   : .aws-sam\build\template.yaml

Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Deploy: sam deploy --guided
```
2度目からは初回のデプロイ時に作成された samconfig.toml を利用するため、 --guide オプションは要りません。

```
$ sam deploy
```
```

        Deploying with following values
        ===============================
        Stack name                 : ApiGateway-Lambda
        Region                     : ap-northeast-1
        Confirm changeset          : True
        Deployment s3 bucket       : aws-sam-cli-managed-default-svamclisourcebucket-xxx
        Capabilities               : ["CAPABILITY_IAM"]
        Parameter overrides        : {}


-----------
長いので省略
-----------


Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y


-----------
長いので省略
-----------


Successfully created/updated stack - ApiGateway-Lambda in ap-northeast-1

```

![sam-8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/321137/6fe11f38-d499-f096-0616-b953e10f2a36.png)

## 削除
CloudFormation からスタックを削除するだけでいいです。
削除に失敗した場合はおそらく、「sum deploy 時に作成された S3 の参照が〜」というようなエラーが出てると思われるので、該当バケットを削除してから再度削除しましょう。
また、コンソールでの作成同様に CloudWatch Logs のログストリームも削除しておくと良いかと思います。


以上です。
AWS SAM 圧倒的に楽だと思いませんか？？？
ただ、内部でも利用している CloudFormation の方が自由度は高いので、もっと勉強してどちらも自在に操れるようになりたいですね。