serverless-plugin-scripts を使ってAPI Gateway REST API をステージに自動デプロイする



## 更新したリソースがステージにデプロイされない問題
Serverless Framework でAPI GatewayのREST API をデプロイすると、リソースは更新されるが、ステージへのデプロイは自動で行われない。リソースに更新が入るたびに手動で行うのは不便がすぎるので、少し手を加えて自動でできるようにしたい。

※ 初回デプロイ時は自動でステージにリソースが反映される。更新時はされない。

## 解決方法
serverless-plugin-scripts というServerless Frameworkのプラグインを利用する。

https://www.serverless.com/plugins/serverless-plugin-scripts

下記の機能がある。

1. カスタムコマンドの作成
2. deployなどServerless Frameworkのイベントに紐づけて、コマンドを実行

今回は2つ目の機能を使って、deployに終了後に、AWS CLI でAPI Gatewayのリソースをデプロイする。

### 1. serverless-plugin-scripts をインストール
下記コマンドを実行

`npm install --save serverless-plugin-scripts`


### 2. deployに紐付けるスクリプトを用意

対象のAPI IDとデプロイ先のstageを引数として渡し、`create-deployment`を実行するコマンドを用意。

``` sh
# !/bin/bash

# 引数の確認
if [ $# -ne 2 ]; then
  echo "Usage: $1 <STAGE>"
  echo "Usage: $2 <REST_API_ID>"
  exit 1
fi

STAGE=$1
REST_API_ID=$2


echo "Deploying to AWS API Gateway..."

# AWS CLIを使用してAPI Gatewayにデプロイ
aws apigateway create-deployment \
  --rest-api-id $REST_API_ID \
  --stage-name $STAGE \

echo "Deployment finished."
```

### 3. serverless.yml を編集

custom に下記のような記述を追加。
hooksを使うとServerless Frameworkのイベントにコマンドを紐づけることができる。
どのようなイベントがあるのかは下記をリンクを参照
https://gist.github.com/HyperBrain/50d38027a8f57778d5b0f135d80ea406

```
  scripts:
    hooks:
      '<紐付けるイベント>': <紐付けるコマンド>
```

``` yaml
service: apigw-sample

frameworkVersion: '3'

plugins:
  - serverless-plugin-scripts # プラグインを追加

custom:
  defaultStage: dev	
  scripts: 
    hooks: # deploy に紐付けるため、hooksを使用
      # deploy終了時に引数を設定し、ステージへのデプロイを実行
      'deploy:finalize': bash deploy_api.sh ${self:provider.stage} ${cf:apigw-sample-dev.restApiId}


provider:
  name: aws
  runtime: python3.9
  stage: ${opt:stage, self:custom.defaultStage}
  region: ap-northeast-1

package:
  patterns:
    - '!**/**'
    - resources/**

resources:
  - ${file(./resources/apigateway.yml)}
```

**補足**
`${cf:apigw-sample-dev.restApiId}` はCloudFormation テンプレートのOutputsをserverless.ymlから参照する時に用いる記法。詳しくは下記の記事を参照

https://dev.classmethod.jp/articles/serverless-framework-ref-cloudformation-outputs/

## 実行

実行前のリソースが↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703223/efd880fb-77fc-a69b-cd16-9541720d041e.png)

ルートのメソッドを`GET /` → `PUT /` に変更する。
テンプレートの該当箇所を変更。

``` yaml
  ApiGatewayMethodRootGet:
    Type: AWS::ApiGateway::Method
    Properties:
      RestApiId: !Ref ApiGatewayRestApi 
      ResourceId: !GetAtt ApiGatewayRestApi.RootResourceId
      HttpMethod: PUT # ←ここを変更
      AuthorizationType: NONE 
      Integration:
        Type: HTTP
        IntegrationHttpMethod: PUT
        Uri: !Sub 'https://${ApiGatewayRestApi}.execute-api.${AWS::Region}.amazonaws.com/' 
```


`sls deploy` を実行。

`Deploying to AWS API Gateway...` と表示されているので、deployコマンドに紐づいてスクリプトも実行されている。

```
$ sls deploy

Deploying apigw-sample to stage dev (ap-northeast-1)
Deploying to AWS API Gateway...
{
    "id": "8vlyj4",
    "createdDate": "2023-06-01T19:54:56+09:00"
}

Deployment finished.

✔ Service deployed to stack apigw-sample-dev (27s)


Need a faster logging experience than CloudWatch? Try our Dev Mode in Console: run "serverless dev"
```

ステージを確認すると、ちゃんと更新できている。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2703223/0f4e51da-e6c8-bf59-4f00-4d208d5d5bd6.png)

## 参考文献
https://www.serverless.com/plugins/serverless-plugin-scripts

https://dev.classmethod.jp/articles/create-serverless-framework-plugin-for-specific-action-before-deploy/