【axios+SAM+API Gateway】localhostからapiを叩けるようになるために苦労した話 （1/3）SAMを利用して、API Gateway及びlambdaを構築

# はじめに
APIの経験がないから、試してみたい
→`axios`というのがいいらしい

コーディングに注力したい（楽をしたい）
→`AWS API Gateway`を使おう

どうせなら構成はコード管理したい
→`SAM`を使おう

というわけで以下の構成を考えてみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586524/3d71271f-b66c-8dbb-58c6-c0b1da340e9f.png)

フロント及びバックエンド両方とも処理部分はとてもシンプルなものにしたのですが、
それでも「`SAM`ってどうやるの？」「`GET`メソッドがローカルから叩けない…」「`GET`が
できたと思ったら、今度は`POST`が叩けない…」等々でだいぶハマりました。

本稿では「ローカルから`GET`及び`POST`メソッドの`API`を叩く」までを振り返り、
私が躓いたところをまとめようと思います。

※開発環境はMacです。
# やったこと
今回私は以下のような流れで進めました。<br>
1. `SAM`を利用して、`API Gateway`及び`lambda`を構築
1. ローカルから先程作成した`API Gateway`の`GET`メソッドを叩く
1. ローカルから先程作成した`API Gateway`の`POST`メソッドを叩く

今回は各ステップの内容について計3回に分けて触れていきたいと思います。

## 1. `SAM`を利用して、`API Gateway`及び`lambda`を構築
`SAM`とは、`Serverless Application Model`の略で、サーバーレスアプリケーション構築用のオープンソースフレームワークです。`CloudFormation`のサーバーレスリソース用に特化したようなもので、`CloudFormation`と併用する事もできます。これを利用することで、各リソースをコード管理することができます。

`SAM`を利用するためには、事前に`AWS SAM CLI`をインストールする必要があります（公式ドキュメントは[こちら](https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html)）。その後、`sam init`を入力し、ウィザードに従って初期化します。以下に私が今回実行した例を載せます。

```
$sam init
Which template source would you like to use?
	1 - AWS Quick Start Templates
	2 - Custom Template Location
Choice: 1 ←1を選ぶといい感じの雛形を作ってくれるので、最初はこっちのほうがいいと思います。

Which runtime would you like to use?
	1 - nodejs12.x
	2 - python3.8
	3 - ruby2.7
	4 - go1.x
	5 - java11
	6 - dotnetcore3.1
	7 - nodejs10.x
	8 - python3.7
	9 - python3.6
	10 - python2.7
	11 - ruby2.5
	12 - java8
	13 - dotnetcore2.1
Runtime: 8 ←ランタイムを決めるところ。お好きなのをどうぞ。

Project name [sam-app]: demo-sam-app ←今回SAMで作成するプロジェクト名。

Cloning app templates from https://github.com/awslabs/aws-sam-cli-app-templates.git

AWS quick start application templates:
	1 - Hello World Example
	2 - EventBridge Hello World
	3 - EventBridge App from scratch (100+ Event Schemas)
	4 - Step Functions Sample App (Stock Trader)
Template selection: 1 ←どんなテンプレートを利用するか。今回は1を利用

-----------------------
Generating application:
-----------------------
Name: demo-sam-app
Runtime: python3.7
Dependency Manager: pip
Application Template: hello-world
Output Directory: .

Next steps can be found in the README file at ./demo-sam-app/README.md
```
そうすると、先程入力したプロジェクト名でディレクトリが作成されているので、そこに移動すると、以下の構成になっています。

```
demo-sam-app/
           ┃━events/
           ┃      ┗event.json
           ┃
           ┃━hello_world/
           ┃           ┃━__init__.py
           ┃           ┃
           ┃           ┃━app.py
           ┃           ┃
           ┃           ┗requirement.txt
           ┃
           ┃━test/
           ┃    ┗unit/
           ┃        ┃━__init__.py
           ┃        ┃
           ┃        ┗test_handler.py
           ┃
           ┃
           ┃━.gitignore
           ┃
           ┃━README.md
           ┃
           ┗template.yaml
```
重要なのは、`template.yaml`でここでどんなアプリケーションの構成にするか記述します。
以下に`Resources`部分を抜粋します。

```
Resources:
  HelloWorldFunction:
    Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
    Properties:
      CodeUri: hello_world/
      Handler: app.lambda_handler
      Runtime: python3.7
      Events:
        HelloWorld:
          Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
          Properties:
            Path: /hello
            Method: get
```
要点をかいつまんで説明すると、

* Type: AWS::Serverless::Function
本リソースの種類。今回は`lambda`。
* CodeUri: hello_world/
本リソースを構成するコードはどこにあるか（今回は`./hello_world`）。
* Type: Api
リソース属性。今回は`Api`となっているので、「この関数は`API Gateway`を介して呼ばれるものですよ」ということを言っている。こうすると勝手に対応した`API Gateway`を作成してくれるので便利！
* Path: /hello
`API`のパス（`URL`の指定）。
* Method: get
`API`のメソッド。

という感じです。
では、本リソースをビルド・デプロイしたいと思います。ビルドには `sam build`、デプロイには`sam deploy`を利用します。初回デプロイは`sam deploy --guided`としたほうがいいです。`sam deploy --guided`としたときにいくつかの選択肢がでます。ここで`Save arguments to samconfig.toml [Y/n]: y`とすることで、次回以降今回入力した情報を引き継いでくれるので、`--guided`が不要になります。

```
$ sam deploy --guided
Looking for samconfig.toml :  Not found

Setting default arguments for 'sam deploy'
=========================================
Stack Name [sam-app]: demo-sam-app
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
HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y
Save arguments to samconfig.toml [Y/n]: y ←これ
```
これでテンプレートにかかれた内容を元に、`API Gateway`及び`lambda`が作成されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586524/a49cf34c-3b72-4958-0d38-b9b4e1455d65.png)

では今回作成した`API`を`curl`を利用して叩いてみたいと思います。

```
$ curl https://{メソッドのURL}/Prod/hello
{"message": "hello world!"}
```
確かにメッセージが返ってきたことが確認できました。

# 終わりに
今回はSAMを使ったAPI環境の構築を行いました。次回はlocalhostを立てて、そこからAPIを叩いた際に直面した問題について触れたいと思います。