エラーの内容
AWS SAM で AWS::Serverless::Api リソースと AWS::ApiGateway::ApiKey および AWS::ApiGateway::UsagePlan
リソースを同じテンプレート内で指定し、デプロイすると以下のエラーで作成に失敗しました。
以下はCloudFormationのコンソールに出力されるエラーメッセージです。
Invalid stage identifier specified # API キーの CREATE_FAILED
API Stage not found: <APIの物理ID>:<ステージ名> # 使用量プランの CREATE_FAILED
原因としては、AWS::Serverless::Api リソースで APIステージのデプロイが行われる前に
AWS::ApiGateway::ApiKey および AWS::ApiGateway::UsagePlan リソースによる使用量プランの
作成がはじまってしまい、ステージの指定に問題があるというエラーになっているようです。
どう対処したか
ワークアラウンドとして、DependsOn プロパティに デプロイメントステージの論理IPを追記したところ
CloudFormation のデプロイが正常終了しました。
この論理IDは テンプレート内で明示的に作成していませんが、AWS::Serverless::Api リソースによって
作成されるため、
- <APIの論理ID>Stage
という形式で指定します。
エラーがでるテンプレート例
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Description: Sample API
Parameters:
EnvType:
Description: Type of API Gateway stage.
Default: dev
Type: String
AllowedValues:
- dev
- stg
- prd
ConstraintDescription: must specify dev or stg or prd.
ProjectName:
Description: Project name.
Default: samplepj
Type: String
MinLength: "3"
MaxLength: "10"
AllowedPattern: "[a-zA-Z0-9]*"
ConstraintDescription: must specify Project name.
Resources:
# Create API Gateway from swagger
Api:
Type: AWS::Serverless::Api
Properties:
DefinitionUri: ./templates/swagger-apigateway.yaml
StageName: !Ref EnvType
# Create API Key
ApiKey:
Type: AWS::ApiGateway::ApiKey
DependsOn:
- Api
Properties:
Enabled: "true"
StageKeys:
- RestApiId: !Ref Api
StageName: !Ref EnvType
Name: !Join
- '-'
- - !Ref EnvType
- !Ref ProjectName
- 'apikey'
# Create API Usage Plan
ApiUsagePlan:
Type: AWS::ApiGateway::UsagePlan
DependsOn:
- Api
Properties:
ApiStages:
- ApiId: !Ref Api
Stage: !Ref EnvType
UsagePlanName: !Join
- '-'
- - !Ref EnvType
- !Ref ProjectName
- 'usageplan'
# Link API Key and Usage Plan
ApiUsagePlanKey:
Type: AWS::ApiGateway::UsagePlanKey
DependsOn:
- ApiKey
- ApiUsagePlan
Properties :
KeyId: !Ref ApiKey
KeyType: API_KEY
UsagePlanId: !Ref ApiUsagePlan
上記のテンプレートを package 後、deploy すると ApiUsagePlan と ApiKey の作成に失敗します。
正常終了するテンプレート例
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Description: Sample API
Parameters:
EnvType:
Description: Type of API Gateway stage.
Default: dev
Type: String
AllowedValues:
- dev
- stg
- prd
ConstraintDescription: must specify dev or stg or prd.
ProjectName:
Description: Project name.
Default: samplepj
Type: String
MinLength: "3"
MaxLength: "10"
AllowedPattern: "[a-zA-Z0-9]*"
ConstraintDescription: must specify Project name.
Resources:
# Create API Gateway from swagger
Api:
Type: AWS::Serverless::Api
Properties:
DefinitionUri: ./templates/swagger-apigateway.yaml
StageName: !Ref EnvType
# Create API Key
ApiKey:
Type: AWS::ApiGateway::ApiKey
DependsOn:
- Api
- ApiStage # ★追記
Properties:
Enabled: "true"
StageKeys:
- RestApiId: !Ref Api
StageName: !Ref EnvType
Name: !Join
- '-'
- - !Ref EnvType
- !Ref ProjectName
- 'apikey'
# Create API Usage Plan
ApiUsagePlan:
Type: AWS::ApiGateway::UsagePlan
DependsOn:
- Api
- ApiStage # ★追記
Properties:
ApiStages:
- ApiId: !Ref Api
Stage: !Ref EnvType
UsagePlanName: !Join
- '-'
- - !Ref EnvType
- !Ref ProjectName
- 'usageplan'
# Link API Key and Usage Plan
ApiUsagePlanKey:
Type: AWS::ApiGateway::UsagePlanKey
DependsOn:
- ApiKey
- ApiUsagePlan
Properties :
KeyId: !Ref ApiKey
KeyType: API_KEY
UsagePlanId: !Ref ApiUsagePlan
ApiUsagePlan と ApiKey の DependsOn プロパティに <APIの論理ID>Stage を追記します。
今回 API の論理ID をそのまま Api としているので、ステージの論理IDは ApiStage です。
ステージのデプロイメントが先に行われ、使用量プランとAPIキーの作成にも成功しました。
補足
AWS SAM 1.4.0 の リリースノート によれば 以下のように Refなどの組み込み関数でAPI Gateway Stage
とAPI Gateway Deployment の論理IDを取得できます。
!Ref MyApi.Stage #SAMによって生成されたステージを参照
!Ref MyApi.Deployment #SAMによって生成されたデプロイメントリソースを参照
しかし DepedsOn プロパティは文字列のみ指定可能であるため、今回の対応では直接記述しました。
特にデプロイメントリソースについては、API のデプロイ毎に論理IDが変化するので組み込み関数による
参照は重要ですね。
以上です。
参考になれば幸いです。