How to solve a circular dependency in SAM Docs while putting API endpoint in the lambda function's environment variables

Viewed 282
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: hello
Resources:
  ApiGatewayApi:
  Type: AWS::Serverless::Api
  Properties:
    StageName: stage
    TracingEnabled: true
  FunctionA:
    ...
    Environment:
      Variables:
        TEST: !Ref ApiGatewayApi
    Events:
      GetUsers:
        Type: Api
        Properties:
          Path: /account
          Method: get
          RestApiId:
            Ref: ApiGatewayApi
  FunctionB:
    ...
    Environment:
      Variables:
        API_URL: !GetAtt ApiGatewayApi.RootResourceId
    Events:
      OrderEvent:
        Type: SQS
        Properties:
          Queue: !GetAtt OrderServiceQueue.Arn

This leads to a circular dependency. IF I do !Ref in a function that does not have an event with API, it does not complain about it. I read the premium support article from aws, blogs and other stack overflow questions but they are not similar to my question.

FunctionB successfully refers to the API gateway id while FunctionA does not.

I create the api outside the function, so I think it SHOULD !Ref the endpoint in it. Is there something else?

1 Answers

The circular reference is created by how AWS SAM uses the events in order to create the definition of the API. This basically means that it needs the ARNs of the lambda functions to construct this definition before it can create the API. But since you are needing IDs of the API in order to create the lambda, you end up with a circular reference since neither can be created without the other one already existing.

The first way to solve this problem is by deploying your stacks in multiple steps. You could first deploy an empty API, which would allow you to reference the API IDs when adding the lambdas. The significant drawback of this approach is of course if you want to easily replicate this stack on another account or redeploying the API for some reason, which means you'd have to use this trick again each time.

Another way, if you really want to have this value as an environment variable, would be to manually create the definition body for the API (in which you construct the ARNs of the lambda, not reference them) and presumably, you'll also need to manually create the permissions in order to allow your API Gateway resource to execute the lambda functions.

However, a better way I feel would be to use the lambda proxy integration (which is used by default I think, but I could not find any documentation to verify this). When using the lambda proxy integration, the incoming event in lambda contains all the information about the API. You could easily extract the information you need from that event instead of having it as an environment variable, but this depends on your exact use case.

Related