Amplify CLIを使って、ローカルで実行＆AWSにデプロイ

Amplify CLIを使って、REST APIや静的コンテンツのサーバを立ち上げます。
ローカル環境で実行・デバッグして確認したのち、AWS上にデプロイ・実行します。

ローカル環境でのデバッグには、node.jsとVisual Studio Codeを使います。
AWS上には、API Gateway、Lambda、S3を使います。
上記の橋渡しに、Amplify CLIを使います。

今回使うのは、AmplifyではなくAmplify CLIです。
なぜこのような言い方をしているかというと、Amplifyは、いろいろ自動化してくれているのですが、何をしているかよくわからないので、長期的にメンテナンスがしづらく、バグに遭遇する可能性もあるためです。
なので、Amplify CLIを使って、API Gateway、Lambda、S3を一つ一つ作っていきます。

それと、Amplifyで構築すると、今までS3やAPI Gateway、Lambdaにばらばらで分散していたパーツ群がAmplifyに集約されるので、まとめてみやすくなります。

目指す形は以下の通りです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/053187f8-7790-d063-a085-3e0f2dfc5883.png)

AWS側は、典型的な構成としており、HTMLやCSS、Javascriptといった静的コンテンツをS3に配置して公開し、WebAPIは、API Gatewayを介してLambdaで処理する構成です。
CloudFrontを前面に配置したり、不揮発データのためのDynamoDBも設定可能ですが、今回は一番単純な構成を想定して省きました。

AWS Lambda上でのデバッグは結構めんどいので、ローカルPCにインストールしたNode.jsとVisual Studio Codeを使って、ブレークポイントを入れたりしてデバッグできるようにします。

AWS側とローカル実行環境が連動できるように、ツール類をGitHubに上げておきました。以降は、これをもとに説明します。

poruruba/amplify_template

https://github.com/poruruba/amplify_template

#準備

以下の準備ができている前提です。たくさんの有志の方が記事で公開していますので参考にして実施しておきます。

・AWSアカウントを持っていること
・AWS CLIがインストールされていること。
・AWSのクレデンシャルが設定されていること（aws configureの実行のことです）
・ローカルPCにNode.jsがインストールされていること
・Amplify CLIがインストールされていること（npm install -g @aws-amplify/cliの実行のことです）

ちなみに、以降私は、Node.js v12.22.5で実施しました。

#環境構築

まずは、プロジェクトとしての環境を構築します。
以下のGitHubからZIPをダウンロードし、適当な名前のフォルダに展開します。例えば、「amplify_sample」とか。

https://github.com/poruruba/amplify_template

```
> unzip amplify_template-main.zip
> mv amplify_template-main amplify_sample
> cd amplify_sample
> npm install
```

一応、これだけでも、Node.jsサーバを立ち上げることができます。

```
> npm run start
```

ポート番号はデフォルトで20080ですが、.envファイルを生成して、以下のようにすれば変更できます。

```.env
PORT=80
```

ブラウザで開くと、publicフォルダの内容が表示されます。

　http://localhost:20080

次に、Amplifyが利用できるように準備します。
「amplify init」です。

```
> amplify init
Note: It is recommended to run this command from the root of your app directory
? Enter a name for the project amplifysample
The following configuration will be applied:

Project information
| Name: amplifysample
| Environment: dev
| Default editor: Visual Studio Code
| App type: javascript
| Javascript framework: none
| Source Directory Path: src
| Distribution Directory Path: dist
| Build Command: npm.cmd run-script build
| Start Command: npm.cmd run-script start

? Initialize the project with the above configuration? Yes
Using default provider  awscloudformation
? Select the authentication method you want to use: AWS profile
? Please choose the profile you want to use default
Adding backend environment dev to AWS Amplify app: d2le0i19kwl1xp
- Initializing project in the cloud...
√ Successfully created initial AWS cloud resources for deployments.
√ Initialized provider successfully.
Initialized your environment successfully.

Your project has been successfully initialized and connected to the cloud!

Some next steps:
"amplify status" will show you what you've added already and if it's locally configured or deployed
"amplify add <category>" will allow you to add features like user login or a backend API
"amplify push" will build all your local backend resources and provision it in the cloud
"amplify console" to open the Amplify Console and view your project status
"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud

Pro tip:
Try "amplify add api" to create a backend API and then "amplify push" to deploy everything
```

これによって、src、amplifyというフォルダが追加されています。大事なのは後者の方です。
※.gitignore も書き換わってしまうので要注意です。



AWSのWeb管理コンソールにも、Amplifyのアプリが作られています。
今回の場合は、amplifysampleという名前になっているかと思います。

　https://ap-northeast-1.console.aws.amazon.com/amplify/home?region=ap-northeast-1#/


#apiとfunctionの作成

Amplifyでapiとfunctionを作成します。
apiはAPI Gatewayのことで、functionはLambdaのことです。
RESTかGraphQLか聞かれますが、馴染みのあるRESTを選択します。
今回は、/sample-get という名前のHTTP Getのエンドポイントを作ってみます。
「amplify add api」です。

```
> amplify add api
? Select from one of the below mentioned services: REST
√ Provide a friendly name for your resource to be used as a label for this category in the project: · apiXXXXXXXX
√ Provide a path (e.g., /book/{isbn}): · /sample-get
Only one option for [Choose a Lambda source]. Selecting [Create a new Lambda function].
? Provide an AWS Lambda function name: amplifysamplefXXXXXXXX
? Choose the runtime that you want to use: NodeJS
? Choose the function template that you want to use: Hello World

Available advanced settings:
- Resource access permissions
- Scheduled recurring invocation
- Lambda layers configuration
- Environment variables configuration
- Secret values configuration

? Do you want to configure advanced settings? No
? Do you want to edit the local lambda function now? No
Successfully added resource amplifysampleXXXXXXXX locally.

Next steps:
Check out sample function code generated in <project-dir>/amplify/backend/function/amplifysampleXXXXXXXX/src
"amplify function build" builds all of your functions currently in the project
"amplify mock function <functionName>" runs your function locally
To access AWS resources outside of this Amplify app, edit the C:\Users\XXXXX\Documents\Node_Projects\amplify_sample\amplify\backend\function\amplifysampleXXXXXX\custom-policies.json
"amplify push" builds all of your local backend resources and provisions them in the cloud
"amplify publish" builds all of your local backend and front-end resources (if you added hosting category) and provisions them in the cloud
✅ Succesfully added the Lambda function locally
√ Restrict API access? (Y/n) · no
√ Do you want to add another path? (y/N) · no
✅ Successfully added resource apie7e19083 locally

✅ Some next steps:
"amplify push" will build all your local backend resources and provision it in the cloud
"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud
```

Amplifyの名前を聞かれますがとりあえずデフォルトで提案された名前をそのまま使っています。
以上で、ローカルフォルダにAPI GatewayとLambdaの準備ができましたが、AWS上にはまだ展開されていません。

さらにエンドポイントを追加したり、既存のLambdaを新規に追加するエンドポイントに追加したりする場合も「amplify add api」を使います。

#ローカル環境で実行・デバッグ

AWSに上げる前に、まずはローカル環境で動作を確認します。
Visual Studio Codeで開いてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/b7e62855-a60f-8810-0867-600feaadef9e.png)

そして、実行とデバッグボタンを押下して、Node.jsを選択するとNode.jsサーバが起動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/9a9b7d34-1beb-96f6-a59a-d5d17e4346fc.png)

さて、先ほど作成したローカルフォルダのLambdaは、``` amplify\backend\function``` というフォルダの配下に配置されています。適当に振られた名前のフォルダがあるはずです。
これが、エンドポイント「/sample-get」のLambdaです。どのフォルダがどのエンドポイントに対応づいているかは、``` amplify\backend\api\[api名]\cli-inputs.json``` で確認できます。

Lambdaのフォルダにあるsrcフォルダに、swagger.yamlを作成します。AWSにアップロードする際には不要ですが、ローカルで実行するときのエンドポイント情報として参照します。

```yaml:amplify\backend\function\XXXXX\src\swagger.yaml
paths:
  /sample-post:
    get:
      responses:
        200:
          description: Success
          schema:
            type: string
```

もう一度起動すると、コンソールにエンドポイントが追加されているのがわかります。

```
> amplify_template@1.0.0 start C:\Users\XXXXX\Documents\Node_Projects\amplify_sample
> node app.js

THIS_BASE_PATH: C:\Users\XXXXX\Documents\Node_Projects\amplify_sample
/swagger get handler {"operationId":"endpoints","func_type":"normal","content_type":"application/json","handler":"handler","files":[],"method":"get"}
/cron get handler {"operationId":"endpoints","func_type":"normal","content_type":"application/json","handler":"handler","files":[],"method":"get"}
/mqtt get handler {"operationId":"endpoints","func_type":"normal","content_type":"application/json","handler":"handler","files":[],"method":"get"}
/sample-get get handler {"operationId":"amplifysampleXXXXXXXX","func_type":"normal","content_type":"application/json","handler":"handler","files":[],"method":"get"}
BasePath: /
can not load mqtt
can not load https
http PORT=20080
```

ブラウザで、http://localhost:20080/sample-get を開くと、以下の文字列が返ってきます。

```
"Hello from Lambda!"
```

もちろん、Visual Studio Code上で実行すれば、ブレークポイントを張ったところで止まります。

#AWS上にデプロイ

それでは、いよいよAWS上にデプロイします。
「amplify push」を実行するだけです。

```
> amplify push
√ Successfully pulled backend environment dev from the cloud.

    Current Environment: dev

┌──────────┬───────────────────────┬───────────┬───────────────────┐
│ Category │ Resource name         │ Operation │ Provider plugin   │
├──────────┼───────────────────────┼───────────┼───────────────────┤
│ Function │ amplifysampleXXXXxXXX │ Create    │ awscloudformation │
├──────────┼───────────────────────┼───────────┼───────────────────┤
│ Api      │ apiXXXXXXXX           │ Create    │ awscloudformation │
└──────────┴───────────────────────┴───────────┴───────────────────┘
? Are you sure you want to continue? Yes
- Updating resources in the cloud. This may take a few minutes...
・・・
√ All resources are updated in the cloud

REST API endpoint: https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/dev
```

最後に、構築されたAPI GatewayのURLが表示されています。ブラウザで以下を開くと、同様の返答が返るはずです。

　https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/dev/sample-get

追加したLambdaは、管理コンソールのAmplifyのページでも、Lambdaのページでも確認できます。
アプリケーションとしてLambdaが管理されているので、管理しやすいです。

#静的コンテンツをアップする

次は、HTML等の静的コンテンツをS3にアップします。
以下を実行することで、静的コンテンツをアップする器であるS3の準備ができます。
「amplify add hosting」です。

```
> amplify add hosting
? Select the plugin module to execute Amazon CloudFront and S3
? Select the environment setup: DEV (S3 only with HTTP)
? hosting bucket name amplifysample-XXXXXXXXXXXXXX-hostingbucket
? index doc for the website index.html
? error doc for the website index.html

You can now publish your app using the following command:
Command: amplify publish
```

Amplify Consoleで作るか聞かれますが、それで作るとAWSの内部で何をしているかわからなくなるので、Amazon CloudFront and S3を選択します。
そして、S3 onlyかS3 with CloudFrontかを聞かれますので、今回は単純なS3のみにします。ちなみに、追加できるhostingは１つのみです。

実際のコンテンツは、distフォルダに置いたものがアップされるようですので、npmスクリプト「npm run build」で、publicフォルダの内容をdistフォルダにコピーするようにしました。
そうすと、以下のAmplifyコマンドを実行すると、そのスクリプトを呼んだうえでdistフォルダの内容をS3にアップしてくれます。
「amplify publish」です。

```
> amplify publish
√ Successfully pulled backend environment dev from the cloud.

    Current Environment: dev

┌──────────┬───────────────────────┬───────────┬───────────────────┐
│ Category │ Resource name         │ Operation │ Provider plugin   │
├──────────┼───────────────────────┼───────────┼───────────────────┤
│ Hosting  │ S3AndCloudFront       │ Create    │ awscloudformation │
├──────────┼───────────────────────┼───────────┼───────────────────┤
│ Function │ amplifysampleXXXXXXXX │ No Change │ awscloudformation │
├──────────┼───────────────────────┼───────────┼───────────────────┤
│ Api      │ apiXXXXXXXX           │ No Change │ awscloudformation │
└──────────┴───────────────────────┴───────────┴───────────────────┘
? Are you sure you want to continue? Yes
・・・
√ All resources are updated in the cloud

Hosting endpoint: http://amplifysample-XXXXXXXXXXXXXX-hostingbucket-dev.s3-website-ap-northeast-1.amazonaws.com

>amplify_template@1.0.0 build C:\Users\XXXXX\Documents\Node_Projects\amplify_sample
> node scripts/copyall.js

copy /public to /dist
frontend build command exited with code 0
Publish started for S3AndCloudFront
√ Uploaded files successfully.
Your app is published successfully.
http://amplifysample-XXXXXXXXXXXXXX-hostingbucket-dev.s3-website-ap-northeast-1.amazonaws.com
```

完了すると、最後にURLが表示されるので、ブラウザで開きます。
publicフォルダの内容が表示されます。ただ、このURLはHTTPなので、HTTPSで開きたいところです。
その場合は、以下に読み替えてください。(微妙にホスト名が異なります）

　https://amplifysample-XXXXXXXXXXXXXX-hostingbucket-dev.s3.ap-northeast-1.amazonaws.com/index.html

#主要なAmplify CLIコマンド

これまで出てきたAmplify CLIのコマンドをまとめます。

amplify init
・Amplifyの準備をします。一番最初に実行します。

amplify add api
・API Gatewayにエンドポイントを作成し、Lambdaと関連付けます。場合に応じて、既存のAPI Gatewayにエンドポイントを追加したり、既存のLambdaにエンドポイントを関連付けます。

amplify update api
・エンドポイントを追加したり削除したりします。

amplify remove api
・API Gatewayを削除します。

amplify add function
・Lambdaを追加します。

amplify remove function
・Lambdaを削除します。

amplify add hosting
・静的コンテンツ用のS3の設定を追加します。

amplify remove hosting
・静的コンテンツ用のS3の設定を削除します。

amplify push
・apiやfunction、hostingの操作結果をAWSに反映します。

amplify publish
・S3に静的コンテンツをアップします。

#終わりに

次は、DynamoDBやカスタムトリガもやってみようと思います。

以上