LoginSignup
7
3

More than 3 years have passed since last update.

Serverless FrameworkでAmazon API Gatewayのベースパスマッピングを作ろうとした時の話

Last updated at Posted at 2019-12-21

この記事は ハンズラボ Advent Calendar 2019 22日目の記事です。
昨日は、@jnuankさんの「来月退職します」から始めるモブプログラミング でした。

はじめまして、今年4月に中途入社し、毎日AWSをがっつり触れて楽しい日々を送る@t-nmrです。
Advent Calendarに参加するの初めてなので何書こうか…?と悩みましたが、
業務でよく触れる機会のあるServerlessで、最近遭遇した内容について書こうと思います。

何があったのか

タイトルにもある通り、ServerlessでAPI Gatewayとそのカスタムドメインを作ろうとしたところ、
ベースパスマッピングが上手く作成出来ず、ちょっとハマってしまう事がありました。

何故かというと、ベースパスマッピングはパスと一緒に対象のステージを指定しなければいけないから。
つまり、初回sls deployの時点ではベースパスマッピング作成のタイミングで
まだメソッドがステージに一度もデプロイされておらず、ステージ自体が無い。

API Gatewayと一緒にfunctionsでAPIのメソッドとなるLambdaを作成していたため、
「自動的にServerlessがデプロイやってくれるんだから、そいつをDependsOnで参照してやればいい」
そんな風に考えて何回か試してみたところ、対象リソースの論理IDの名前がコロコロ変わって予測出来ない。1
(論理IDの名前は「ApiGatewayDeploymentXXXXXXXX」といった感じで毎回名前が異なる)

これじゃDependsOnで参照出来ない。凄く困る。

色々考えた結果

先にAPI GatewayとLambda作ってから2回に分けてリソース構築するとか、
別途スクリプトあたりで作るとかも考えましたが、やっぱりsls deployコマンド一発で作りたいですよね。

という事で、シンプルにserverless.yml中でステージへのデプロイを別途明示的に行い、
その完了をDependsOnで待つ事にしました。

ソースコード

こんな感じになりました (一部記載は簡略化しています)

また余談ですが、Deploymentの際にDependsOnで見ているApiGatewayMethodApiV1TestGetも、
Serverlessが自動的に作ってくれるリソースになります。

しかし、このリソースの論理IDは名前の予測が可能 かつ 普通にDependsOnで指定可能です。

(「ApiGatewayMethod + {APIパスのupper camel case} + {HTTPメソッド} 」 という形式で作成されます。
 慣れてる人には常識かと思いますが、初心者だとこういう部分も知らないと地味にハマりかけたりする…)

functions:
  test:
    handler: lambda.handler
    timeout: 15
    tracing: true
    events:
      - http:
          path: /api/v1/test
          method: get
          cors: true
          integration: lambda-proxy

resources:
  Resources:
    ApiGatewayRestApi:
      Type: AWS::ApiGateway::RestApi
      Properties:
        Name: test-api
        ApiKeySourceType: HEADER
        EndpointConfiguration:
          Types:
            - REGIONAL

    ApiGatewayDomainName:
      Type: AWS::ApiGateway::DomainName
      Properties: 
        DomainName: ${self:custom.domain_name}
        EndpointConfiguration: 
          Types: 
            - REGIONAL
        RegionalCertificateArn: ${self:custom.acm_arn_regional}

    # BasePathMappingの依存解決(stage作成)のために、デプロイを個別に実行する
    ApiGatewayDeploy:
      Type: AWS::ApiGateway::Deployment
      DependsOn: ApiGatewayMethodApiV1TestGet
      Properties:
        RestApiId:
          Ref: ApiGatewayRestApi
        StageName: ${self:provider.stage}

    ApiGatewayBasePathMapping:
      Type: AWS::ApiGateway::BasePathMapping
      DependsOn: ApiGatewayDeploy # ここで個別に実行したステージへのデプロイ完了を待つ
      Properties:
        BasePath: ""
        DomainName: ${self:custom.domain_name}
        RestApiId:
          Ref: ApiGatewayRestApi
        Stage: ${self:provider.stage}

めでたしめでたし。

とでも思っていたのか?

はい、ここまで書いておいて全てをひっくり返します。

「デプロイの論理IDの名前がコロコロ変わって予測出来ない」と上で書きましたが違いました。
普通に記述出来る方法がありました。

この記事を書いている最中(Advent Calendar投稿当日)に、念のためServerless Framworkの公式ドキュメントを再調査していたらこんな記載がありました。

あのランダムだと思っていた数字列はInstanceIdとやらで、${sls:instanceId}って感じで参照出来ますと。

つまり、結論としてはAWS::ApiGateway::Deploymentを書く必要は無く、
「ApiGatewayDeployment${sls:instanceId}」というリソースを
ベースパスマッピング作成時にDependsOnで見てやればオッケー。

……… よし、週明けにserverless.ymlを書き直そう!

おわり

公式ドキュメントはちゃんと読もう。おじさんとの約束だ。

明日は@o2346さんです。


  1. そう思っていた時期が私にもありました。 

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3