TutorialbeginnerPart 8 of 18

Connecting Lambda to API Gateway

The Lambda exists, the routes exist, but they don't talk to each other yet.

April 19, 20264 min read

What you'll learn

  • How API Gateway Methods work
  • Connecting a route to a Lambda function
  • Lambda permissions for API Gateway
  • Deployment and Stage resources
Prerequisites:Previous post completed (Adding Lambda to template.yaml)

We have a Lambda function and we have API Gateway routes. But right now they're just sitting there, not talking to each other. The missing piece is the Method resource, this is what connects an HTTP method on a route to a specific Lambda function.

Method resource

A Method tells API Gateway: "When someone sends a GET request to /hello, forward it to this Lambda function." Add this under your Lambda definition:

template.yaml
yaml
> # Lambda
...
# Methods
  GetHelloMethod:
    Type: AWS::ApiGateway::Method
    Properties:
      RestApiId: !Ref RustExample
      ResourceId: !Ref HelloResource
      AuthorizationType: NONE
      HttpMethod: GET
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Sub "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HelloFunction.Arn}/invocations"

Let me explain the important parts:

  • ResourceId: !Ref HelloResource - This points to the /hello route we created in the configuration lesson. The !Ref function grabs the ID of that resource.
  • AuthorizationType: NONE - No authentication required. Anyone can call this endpoint. We'll add auth in a real project, but for learning, this is fine.
  • HttpMethod: GET - This method only responds to GET requests.
  • Type: AWS_PROXY - This is the important one. It tells API Gateway to forward the entire HTTP request to your Lambda as a JSON object. That's why we use ApiGatewayProxyRequest in our Rust code.
  • IntegrationHttpMethod: POST - Yes, this is always POST even though our API method is GET. This is the method API Gateway uses to invoke the Lambda, not the method your client uses.
  • Uri - The ARN of the Lambda function. That long string is just the AWS way of saying "this Lambda function right here."

Warning

IntegrationHttpMethod is always POST for Lambda integrations. This is not a typo. API Gateway invokes Lambda functions using a POST request internally, regardless of what HTTP method the client used.

Lambda permissions

Just because API Gateway knows about your Lambda doesn't mean it's allowed to invoke it. AWS is very strict about permissions. You need to explicitly grant API Gateway permission to call your function:

template.yaml
yaml
> # Methods
...
# Permissions
  HelloFunctionApiPermission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref HelloFunction
      Action: lambda:InvokeFunction
      Principal: apigateway.amazonaws.com
      SourceArn: !Sub "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${RustExample}/*"

The SourceArn uses a wildcard (/*) at the end, which means any method on any route of this API Gateway can invoke the function. This is fine for our tutorial. In production, you'd make this more specific.

Deployment and Stage

Here's something that always trips me up: even after defining everything, your API won't be accessible until you create a Deployment and a Stage. Think of it like this - the Deployment is a snapshot of your API configuration, and the Stage is the environment (like dev or prod) where that snapshot is published.

template.yaml
yaml
> # Permissions
...
# Deployment
  ApiDeployment:
    Type: AWS::ApiGateway::Deployment
    DependsOn:
      - GetHelloMethod
    Properties:
      RestApiId: !Ref RustExample
 
  ApiStage:
    Type: AWS::ApiGateway::Stage
    Properties:
      RestApiId: !Ref RustExample
      DeploymentId: !Ref ApiDeployment
      StageName: !Ref StageName

The DependsOn is important. It tells CloudFormation to wait until the Method is created before creating the Deployment. Without this, the deployment might happen before the methods exist, and you'll get an empty API.

Outputs

Finally, let's add an Outputs section so we can easily find our API URL after deploying:

template.yaml
yaml
Outputs:
  ApiUrl:
    Description: API Gateway endpoint URL
    Value: !Sub "https://${RustExample}.execute-api.${AWS::Region}.amazonaws.com/${StageName}"
  HelloFunctionArn:
    Description: Hello Lambda Function ARN
    Value: !GetAtt HelloFunction.Arn

After deployment, SAM will print these values in the terminal so you know exactly where your API is.

Here's how all the pieces connect now:

Code
Client → GET /hello
  → API Gateway (RustExample)
    → Route (HelloResource: /hello)
      → Method (GetHelloMethod: GET)
        → Integration (AWS_PROXY)
          → Lambda (HelloFunction)
            → Your Rust handler
              → ApiGatewayProxyResponse

Every layer in that chain is something we defined in template.yaml. If any piece is missing, the request won't make it to your code.

Everything is wired up. In the next post, we'll actually build and deploy this to AWS and test it with a real HTTP request.