Deploy to multiple stages with shared API Gateway

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!

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"
1 Like

This is not working. its showing error as ApiGatewayDeploymentDev - The REST API doesn’t contain any methods. Any idea why its showing ?

Someone mentioned this several months ago. All API Gateways must have at least one method defined.

Were you ever able to resolve this? I am having the same issue.

Love how Serverless is making all these enterprise software but haven’t create a solution for a problem that everyone using AWS in a true enterprise level is having.

It does work as detailed by @serkanh.
A method has to be added also, but the idea of putting the two stages and two deployments in the same Resources section works.

It does work but the problem mentioned by @jeremydaly is linked.

I was disappointed that serverless wouldn’t allow that in a more convenient way, but I realised that it made sense: they want each project and deploy to be completely independent. As api gateway is the only service that can handle multiple stage, they just ignored that feature and focused on independent convenient deployments.

Where to add ‘method’ ?

Same level as ‘ApiGatewayRestApi’, root of Resources :

ApiMethodTest:
Type: AWS::ApiGateway::Method
Properties:
HttpMethod: GET
AuthorizationType: NONE
RestApiId:
Ref: ApiGatewayRestApi
ResourceId:
Fn::GetAtt:
- ApiGatewayRestApi
- RootResourceId
Integration:
Type: MOCK
RequestTemplates:
application/json: |
{
“statusCode”: 200
}
IntegrationResponses:
- StatusCode: 200
ResponseTemplates:
application/json: |
{
“statusCode”: 200
}
PassthroughBehavior: WHEN_NO_TEMPLATES