0

I have an application that uses an AWS lambda function triggered by an implicit http api event, which gets post/get requests from a React app:

"mylambda": {
      "Type": "AWS::Serverless::Function",
      "Properties": {
        "InlineCode": "exports.handler = async (event, context)",
        "MemorySize": {
          "Ref": "LambdaMemorySize"
        },
        "Handler": "backend/index.handler",
        "Role": {
          "Fn::GetAtt": ["myrole", "Arn"]
        },
        "Timeout": {
          "Ref": "LambdaTimeout"
        },
        "Runtime": "nodejs12.x",
        "FunctionName": "myFunction",
        "Events": {
          "httpapi": {
            "Type": "HttpApi",
            "Properties": {
              "Path": "/myApi",
              "Method": "ANY"
            }
          }
        }
      }
    }
  },

I want to add an environment variable inside the Lambda function for the http-api endpoint so that I can use it in lambda's handler:

"Environment": {
          "Variables": {
           
            "apiEndpoint": {
              "Fn::Join": [
                "",
                [
                  "https://",
                  { "Ref": "ServerlessHttpApi" },
                  ".execute-api.",
                  { "Ref": "AWS::Region" },
                  ".amazonaws.com"
                ]
              ]
            }
          }
        }

The problem is that this throws a circular dependency error and I can see why (lambda relies on api-gateway and api-gateway relies on lambda).

I tried to create the http-api separately but then there seemed to be no way of referencing the api inside lambda as a trigger i.e. when I deploy, the template creates a lambda function that doesn't have my api as a trigger, while my api was created separately.

I know the whole env variables thing can be done easily from the console but my deployment model assumes everything should be done in the CF template.

An answer here suggested:

"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."

I could do this in the body of the lambda's handler in index.js:

module.exports.apiendpoint = event.requestContext.domainName;

But this will collide with the fact that 1) I can't use index.js variables that are outside React's src folder and 2) I'm not sure how the app will run for the first time since it'll require the get/post request first to trigger lambda.

I think my main problem is simple: I don't know how I can reference the http api endpoint in Lambda's environment variables without throwing an error. Is it that the whole structure of my app is wrong?

Asalmi
  • 29
  • 5
  • Why does the lambda need to have that information? I'm slightly confused by the overall architecture. Could you clarify? – Paolo Oct 09 '21 at 12:50
  • @Paolo The lambda receives an event through the api trigger to add data/files to s3 bucket + dynamodb table. – Asalmi Oct 09 '21 at 13:02
  • Right, so the chain of events is "Api gateway" -> "lambda" -> "s3 bucket dynamodb". Why does the lambda need to have that environment variable ? – Paolo Oct 09 '21 at 13:04
  • The idea is to export the env variable so that it can be used by the application itself (outside the lambda handler). Otherwise how is the application gonna know where to post/get? – Asalmi Oct 09 '21 at 13:14
  • The answer you're referring to, is mine. But I really cannot follow the architecture that your question is based upon. You're trying to add an environment variable to a Lambda function. But I don't understand how that is related to react code in any way (since that is a front-end framework). In the answer you refer to, I also state that you can work around the circularity by manually creating the API body (with constructed lambda ARN) and by manually adding the permission for API GW to trigger your lambda. That could fix your problem I guess. – stijndepestel Oct 11 '21 at 07:59
  • The UI is React, and this is where content is sent over Api/Lambda to S3 and dynamodb. I wanted my app to kick off the moment it's deployed hence my question about exporting the Api endpoint variable to the React UI. I'll try your suggestion as your Q seems to be the closest to mine! – Asalmi Oct 11 '21 at 10:03
  • @Asalmi I still don't really understand why you would add the API endpoint as an environment variable to your lamda function, if you need it in your react code. I assume you're deploying your React application using S3/CloudFront? – stijndepestel Oct 11 '21 at 12:48
  • @stijndepestel When you do say axios.get('url'). Where do you get the URL from? It's an Api endpoint that is created when the Lambda is created. If there is no Lambda, there's no api endpoint i.e. the UI will not be able to make post/get requests. – Asalmi Oct 12 '21 at 09:59
  • @Asalmi I really can't follow your train of thought. You'll have to deploy the lambda and the API, retrieve the URI (either via the AWS Console UI or you could configure it as an output of your cloudformation stack) and then deploy your front-end application which includes your API endpoint. I think there's some design flaw in what you're trying to do (or you have explained it badly). – stijndepestel Oct 12 '21 at 12:26

0 Answers0