AWS AmplifyでREST APIを構築する際の注意点

AWS Amplifyを使ったREST API (Amazon API Gateway + AWS Lambda) の構築を試した過程で判明した注意点を紹介する。<br>※ 情報は2020年12月時点のものであり、AWS Amplifyのアップデートにより改善される可能性がある。

#### 対象バージョン

* AWS Amplify (2020年12月20日時点)
* Amplify CLI 4.40.0

#### REST API構築にまつわる注意点

* 複数プラットフォームのフロントエンドに対して同じバックエンドを共有する構成を作るのに工夫が必要となる。
  * AWS Amplifyではフロントエンドのみ、もしくはフロントエンド＋バックエンドのいずれかの構成でしかプロジェクトを定義できず、共通のバックエンドを単独のプロジェクトとすることができない。
  * フロントエンド＋バックエンドのプロジェクトとしておき、フロントエンドのビルド設定などをダミーの値にしておくことはできるが、Amplify Console (CI/CD) もフロントエンドのみ、もしくはフロントエンド＋バックエンドという組み合わせでしか設定ができないため、毎回無駄なフロントエンドのビルドが走ってしまう。
  * [公式ドキュメント](https://docs.amplify.aws/cli/teams/multi-frontend)ではいずれかのプラットフォームのプロジェクトに定義したバックエンドを他のプラットフォームのプロジェクトで `amplify pull` で共有する方法が紹介されている。
* API Gateway用のAWS Lambdaを `amplify push` でクラウド側に反映する時に `npm install` が実行されるが `--production` フラグが設定されないため、devDependenciesが含まれてパッケージが肥大化してしまう。
  * Amplify CLIでデプロイする場合は、package.jsonをsrcディレクトリに含めずに、`amplify push` 実行前に `npm install --production` を実行して生成されたnode_modulesディレクトリをsrcディレクトリにコピーすることで回避できる。（デプロイスクリプトの作り込みが必要にはなるが。）
  * Amplify Console (CI/CD) を利用する場合は、クラウド側でビルドが実行されるため上記の回避策が取れない。devDependenciesを削ったpackage.jsonをsrcディレクトリに配置することで回避可能であるが、より複雑なスクリプトの作り込みが必要となる。
  * 参考：[Don't install function node_modules on push #4830](https://github.com/aws-amplify/amplify-cli/issues/4830)
* Amplify Console (CI/CD) を利用したLambda Layersの更新機能にバグが多い。
  * CI/CDでのデプロイ時にAWS Lambda Layersの変更検知が上手く動かずLayerのバージョンの更新がされない。（公式ドキュメントではpackage.jsonの変更を検知してバージョンを更新するとあるが、CI/CDでのデプロイではこれが正常に動作しない。）
  * Amplify CLIとAmplify Console (CI/CD) のデプロイを併用した場合にLambda Layersのバージョン番号の順序が崩れる。（参考：[Lambda Layer versions CLI - Console
    #5072](https://github.com/aws-amplify/amplify-cli/issues/5072)）

#### （参考）動作検証内容

##### Lambda Layersを管理する（Amplify CLI）

* 新規のAmplifyプロジェクトを作成する。

  ```
  $ amplify init
  ? Enter a name for the project AmplifyTest
  ? Enter a name for the environment dev
  ? Choose your default editor: None
  ? Choose the type of app that you're building javascript  
  Please tell us about your project
  ? What javascript framework are you using none
  ? Source Directory Path:  src
  ? Distribution Directory Path: dist
  ? Build Command:  npm.cmd run-script build  
  ? Start Command: npm.cmd run-script start
  ```

* Lambda Layerを追加する。

  ```
  $ amplify function add
  ? Select which capability you want to add: Lambda layer (shared code & resource used across functions)
  ? Provide a name for your Lambda layer: amplifytest63f467e9
  ? Select up to 2 compatible runtimes: NodeJS
  ? The current AWS account will always have access to this layer.
  Optionally, configure who else can access this layer. (Hit <Enter> to skip)
  ```

* 追加したLambda Layerを紐づけたREST API (API Gateway + Lambda) を追加する。

  ```
  $ amplify add api
  ? Please 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: apiade58b9c
  ? Provide a path (e.g., /book/{isbn}): /
  ? Choose a Lambda source Create a new Lambda function
  ? Provide an AWS Lambda function name: amplifytest26a6adfe
  ? Choose the runtime that you want to use: NodeJS
  ? Choose the function template that you want to use: Hello World
  ? Do you want to configure advanced settings? Yes
  ? Do you want to access other resources in this project from your Lambda function? No
  ? Do you want to invoke this function on a recurring schedule? No
  ? Do you want to configure Lambda layers for this function? Yes
  ? Provide existing layers or select layers in this project to access from this function (pick up to 5): amplifytest63f467e9
  ? Select a version for amplifytest63f467e9: 1
  ? Do you want to edit the local lambda function now? No 
  ```

* 追加したAPI Gateway + Lambda + Lambda Layerをクラウド側に反映する。

  ```
  amplify push
  ```

* Lambda Layerのモジュールを更新する。

  ```
  cd amplify\backend\function\amplifytest63f467e9\lib\nodejs
  npm i camelcase
  ```

* (この時点でAmplify CLIがLambda Layerのpackage.json変更を検知して、REST API用LambdaのAPIのLambda Layer設定を変更しようとすると新しいバージョンが選択肢に表示される。）

  ```
  amplify function update
  ? Select which capability you want to update: Lambda function (serverless function)
  ? Select the Lambda function you want to update amplifytest26a6adfe
  ? Which setting do you want to update? Lambda layers configuration
  ? Do you want to configure Lambda layers for this function? Yes
  ? Provide existing layers or select layers in this project to access from this function (pick up to 5): amplifytest63f467e9
  ? Select a version for amplifytest63f467e9: (Use arrow keys)
  > 2
  > 1
  ```

* 変更をクラウド側に反映すると、Lambda Layerのバージョンが2に変更される。

  ```
  amplify push
  ```

##### Lambda Layersを管理する（Amplify ConsoleのCI/CD機能）

* Amplify CLIの手順の `amplify init` → `amplify function add` → `amplify function add` を実行する。
* AmplifyプロジェクトをGitHubのPrivateプロジェクトにプッシュして、Amplify ConsoleからGitHubとの連携設定を行う。（手順は[こちら](https://amplify-sns.workshop.aws/ja/70_multi_env/10_amplify_console/connect_github.html)を参考）<br>→ Amplify Consoleのビルド処理で `amplify push` 相当の処理が実行され、クラウド側のリソースが作成される。
* Amplify CLIの手順の「Lambda Layerのモジュールを更新する」を実行する。<br>→ REST API用LambdaのLambda Layerの選択肢は変わらず、 GitHubにプッシュしてもLambda Layerのバージョンも上がらない。