Search code examples
amazon-web-servicesyamlaws-api-gatewayaws-samaws-sam-cli

When creating multiple API Gateway instances in template.yaml, how do you control which Gateway is imitated when running 'sam local start-api'?


I've created a SAM template.yaml file that contains two API Gateway instances - one for production and one for staging. Each has its own stage called Production and Staging respectively and each of these stages have their own Stage Variables which are specific to the environment.

The application I'm building locally has been created using the AWS SAM CLI and I've been using the command 'sam local start-api' to run local instances of an API Gateway to test calling endpoints in postman - which has been working fine. Unfortunately, I now need to start testing endpoints that require stage variables and I can't see any way of telling SAM CLI which of the two API Gateway instances in the template file to imitate. Obviously I don't want it to use Production as that will have data that connects to live services.

I'm aware that I could have created one API Gateway instance that contains two Stages and so, in the event that there isn't a way to do the above, is there a way to get SAM to use a particular stage within an API Gateway instance instead? Below is a snippet from my template file.

ApiProduction:
    Type: AWS::Serverless::Api
    Properties:
      Name: service-layer-production-v1
      StageName: Production
      OpenApiVersion: 3.0.1
      Auth:
        ApiKeyRequired: true
      Variables:
        IS_STAGING: false
        VARIABLE2: value-a
        VARIABLE3: value-a
      Models:
        Error:
          $schema: http://json-schema.org/draft-04/schema#
          title: Error Schema
          type: object
          properties:
            message:
              type: string
        Empty:
          $schema: http://json-schema.org/draft-04/schema#
          title: Empty Schema
          type: object
          properties:
            message:
              type: string

  ApiStaging:
    Type: AWS::Serverless::Api
    Properties:
      Name: service-layer-staging-vnull
      StageName: Staging
      OpenApiVersion: 3.0.1
      Auth:
        ApiKeyRequired: true
      Variables:
        IS_STAGING: true
        VARIABLE2: value-b
        VARIABLE3: value-b
      Models:
        Error:
          $schema: http://json-schema.org/draft-04/schema#
          title: Error Schema
          type: object
          properties:
            message:
              type: string
        Empty:
          $schema: http://json-schema.org/draft-04/schema#
          title: Empty Schema
          type: object
          properties:
            message:
              type: string

Solution

  • You can use cloud formation if condition https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference-conditions.html#intrinsic-function-reference-conditions-if to achieve that.

    Here is a quick example:

    
    # Set expected parameter to be passed to sam local
    Parameters:
      Stage:
        Type: String
        Default: staging
        Description: Parameter for getting the deployment stage
    
    # Create a condition based on the parameter
    Conditions:
      isStagingEnvironment: !Equals
        - Ref: Stage
        - staging
    
    Resources:
    
      MyFunction:
        Type: "AWS::Serverless::Function"
        Properties:
          Events:
            CatchAll:
              Type: Api
              Properties:
                Method: GET
                Path: /my-sample-function
                # If condition to switch which API to use for this event while invoking the function
                RestApiId: !If
                  - isStagingEnvironment
                  - !Ref ApiStaging
                  - !Ref ApiProduction
    

    Then you can run your sam locally this way:

    sam local start-api --parameter-overrides Stage=staging
    

    The same technique can be used if you have multiple stages per single API Gateway.