🐣

[AWS SAM]EventのPathで関数 !Sub や !Ref が使えないという落とし穴

2021/11/09に公開

AWS SAMを触っていて、sam build時に気になるエラーが出てきたのでまとめました。

※まったくAWSのスペシャリストではないので、他に対応方法や、そもそも認識がおかしい所があればコメントで教えて頂けると嬉しいです!

発生したエラーについて

実現したいこと

今回AWS SAMを利用してAPIGateway, Lambdaのベーシックな構成を作成しようとしています。
その中で、実現したいことは以下です。

  • Parameters属性でバージョンを指定できるようにする
  • APIGatewayのAPIエンドポイントにバージョンを含めるようにする
    APIのエンドポイントにはバージョンを含めるのが良いので、https://api/v1/user、のようなエンドポイントを実現したいです。

発生エラー

以下がsam build時に発生するエラーです。

samcli.commands.validate.lib.exceptions.InvalidSamDocumentException: [InvalidResourceException('CreateUser', "Event with id [Event] is invalid. Api Event must have a String specified for 'Path'."),

問題のtemplate.yaml

以下が、関連個所を抜粋したtemplate.yamlです。

Parameters:
  Env:
    Description: Enviroment name; dev, stg, prd.
    Type: String
    Default: dev
  Version:
    Description: Application version; v1, v2, etc.
    Type: String
    Default: v1
 
  CreateUser:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Sub "todo-${Env}-${Version}-create_user"
      CodeUri: functions/user/create/
      Handler: app.lambda_handler
      Events:
        Event:
          Type: Api
          Properties:
            Path: !Sub "/api/${Version}/user" # ★問題の箇所
            Method: post
            RestApiId:
              Ref: UserApi

エラー原因

GitHub の Issues に同じ内容があった

現在Open中で同じ内容のissueがありました。

https://github.com/aws/serverless-application-model/issues/687

公式から返ってきている内容は以下だけのようです。

CFN の組込み関数は、現在 "Path" パラメータではサポートされていません。これは、パスが生成されたswaggerの辞書キーとして必要であり、SAMはすべてのCFN固有関数を解決できないためです。
テンプレートパラメータの値に対しては可能性がありますが、それ以外の値に対してはできないと思います。
イベントを処理したり作成したりする場所のパラメータ値を解決するために、イントリンシックリゾルバを使用して、期待通りに動作することを検証する必要があります。

この返答以降の返答は無いのですがissueはOpen中であり、公式に解決されることは無さそうです。
この解答後にgood-first-issueのラベルも付けているので、解決する気はないけどだれかプルリク出してくれ~という雰囲気を感じます。

拙い英語力を駆使して、関連のissueも読んでみたところ、おおよそ以下のことがわかりました。

  • そもそも対応していない。
  • すぐには対応できず、ドキュメントに注意書きをするくらいの対応しか採られていない?
  • 組み込み関数はCloudFormationの機能なので、SAMの問題とするのは間違っていそう
  • 今回のやり方のまま解決するには、バージョンをハードコーディングするしかなさそう

というわけで、解決できない、が今回の結論になります。

別の解決策を考える

そもそも、APIGatewayのPath部分にバージョンを指定するのが正しいのかも微妙なところです。
別の解決策として、ステージにバージョンを指定してあげる、という方法が考えられます。

以下、APIの部分を抜き出したテンプレート

  UserApi:
    Type: AWS::Serverless::Api
    Properties:
      Name: !Sub "api-${Env}-user-api-${Version}"
      StageName: !Ref Version # ★ここ

このようにすれば、エンドポイントの始まりは必ず、以下のようにバージョンから始まることになります。
https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/v1

ステージ名に/を入れることはできないので、dev/v1などとできないところは少し残念ですが、dev_v1のようにすることは出来るので、ギリギリ許容範囲でしょうか。

まとめ

  1. AWS SAMでは組み込み関数が使えないことがある
  2. issueとして残っているが、数年は解決することが無さそう
  3. 今回の対応としてはとりあえずStageNameにバージョンを入れれば対応可能

他に対応方法や、そもそも認識がおかしい所があればコメントで教えて頂けると嬉しいです!

Discussion