Deploy to multiple stages with shared API Gateway


#1

I’m deploying an API Gateway that is defined in a seperate serverless.yml file as such:

resources:
    Resources:
        HelmApiGateway:
            Type: AWS::ApiGateway::RestApi
            Properties:
                Name: HelmApiGateway
    Outputs:
        HelmApiGatewayId:
            Value:
                Ref: HelmApiGateway
            Export:
                Name: HelmApiGatewayId
        HelmApiGatewayRootResourceId:
            Value:
                Fn::GetAtt:
                    - HelmApiGateway
                    - RootResourceId
            Export:
                Name: HelmApiGatewayRootResourceId

I’m then referencing as:

    apiGateway:
        restApiId:
          Fn::ImportValue: HelmApiGatewayId
        restApiRootResourceId:
          Fn::ImportValue: HelmApiGatewayRootResourceId

However when I deploy on multiple stages I get:

Another resource with the same parent already has this name

How do I deploy to staging and production using a single API Gateway?

Thanks!


#2

You want to use cloudformation directive like below. Basically stage variables are available in ApiGateway stage resources, in order to use them you attach the api gateway stage to deployment. This will give you ability to use same openapi definition to be used in multilple stages so you can point prod lambda functions to /prod api endpoint and dev to /dev api endpoint.
Also if you are using swagger file and need to reference stage variable with $ sign you will need to use variableSyntax: "\\${((?!stageVariables)[ ~:a-zA-Z0-9._'\",\\-\\/\\(\\)]+?)}" to pass $ to your swagger definition. And refer to stage var (say you have stage variable called Stage) in your swagger definition like so:
x-amazon-apigateway-integration:uri: "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:174076265606:function:ha-content-syndication-lambda-${stageVariables.Stage}-images/invocations"

resources:
          Resources:
            ApiGatewayRestApi:
              Type: AWS::ApiGateway::RestApi
              Properties:
                Name: ${self:service}-${self:provider.stage}
                Body: ${file(swagger.yaml)}
         

        ApiGatewayDeploymentDev:
          Type: AWS::ApiGateway::Deployment
          Properties:
            RestApiId:
              Ref: ApiGatewayRestApi
            Description: 'Dev deployment'

        
        ApiGatewayDeploymentProd:
          Type: AWS::ApiGateway::Deployment
          Properties:
            RestApiId:
              Ref: ApiGatewayRestApi
            Description: 'Prod Deployment'

        ApiGatewayStageDev:
            Type: 'AWS::ApiGateway::Stage'
            Properties:
              StageName: dev
              Description: Dev Stage
              RestApiId: 
                Ref: ApiGatewayRestApi
              DeploymentId: 
                Ref: ApiGatewayDeploymentDev
              Variables:
                "Stage": "dev"
        ApiGatewayStageProd:
            Type: 'AWS::ApiGateway::Stage'
            Properties:
              StageName: prod
              Description: Prod Stage
              RestApiId: 
                Ref: ApiGatewayRestApi
              DeploymentId: 
                Ref: ApiGatewayDeploymentProd
              Variables:
                "Stage": "prod"