How to Trigger Lambda from an API Gateway GET Request (HTTP API Step-by-Step)
Wiring an API Gateway GET route to a Lambda function is one of the most common serverless patterns — yet the gap between "it works in the console" and "it works correctly in production" trips up engineers more often than expected. This guide walks through creating an HTTP API with a GET route that invokes Lambda, covering the integration model, permissions, and the CLI commands that make it repeatable.
TL;DR: API Gateway HTTP API → Lambda Integration
| Step | What You're Doing | Why It Matters |
|---|---|---|
| 1 | Create the Lambda function | Target must exist before integration |
| 2 | Create the HTTP API | Defines the API container |
| 3 | Create the Lambda integration | Wires the API to the function |
| 4 | Create the GET route | Maps the HTTP method + path to the integration |
| 5 | Create a stage and deploy | Makes the route publicly reachable |
| 6 | Grant invoke permission | API Gateway must be allowed to call Lambda |
How API Gateway HTTP API Invokes Lambda
Before touching the CLI, understand the model. API Gateway HTTP API uses an AWS_PROXY integration type for Lambda. This means the entire HTTP request — headers, query string, body, path parameters — is serialized into a JSON payload and passed directly to your Lambda function as the event object. Your function is responsible for constructing the HTTP response in the expected format.
The two Lambda payload formats are payload format version 1.0 (compatible with REST API event shape) and 2.0 (simplified, HTTP API native). Version 2.0 is the default for HTTP APIs and produces a leaner event structure. If your function was written for a REST API, verify which format it expects before wiring it to an HTTP API.
Permission is a separate concern from integration. Even after the integration is configured, API Gateway cannot invoke Lambda unless a resource-based policy on the Lambda function explicitly allows it. This is the most common reason a correctly configured route returns a 500 or 403 on first test.
HTTP GET /hello"] --> APIGW["API Gateway
HTTP API"] APIGW --> Route["Route: GET /hello"] Route --> Integration["AWS_PROXY Integration
Payload Format 2.0"] Integration --> Lambda["Lambda Function
hello-api"] Lambda --> Integration Integration --> APIGW APIGW --> Client
- Client sends GET request to the API Gateway invoke URL.
- API Gateway matches the route (
GET /hello) and resolves the attached integration. - Integration serializes the request into a Lambda payload (format 2.0 by default) and invokes the function synchronously.
- Lambda executes and returns a response object with
statusCodeandbody. - API Gateway translates the Lambda response back into an HTTP response and returns it to the client.
Step 1: Create the Lambda Function
The integration target must exist before you can reference it. Create a minimal function to validate the end-to-end flow first — swap in real business logic once routing is confirmed.
Create a deployment package. Save the following as index.mjs:
export const handler = async (event) => {
return {
statusCode: 200,
body: JSON.stringify({ message: "Hello from Lambda" })
};
};
Zip it and create the function:
zip function.zip index.mjs
aws lambda create-function \
--function-name hello-api \
--runtime nodejs20.x \
--role arn:aws:iam::123456789012:role/lambda-basic-execution \
--handler index.handler \
--zip-file fileb://function.zip \
--region us-east-1
The --role must reference an existing IAM role with the AWSLambdaBasicExecutionRole managed policy attached. Replace the account ID and role name with your actual values.
Step 2: Create the HTTP API
HTTP API is the leaner, lower-latency successor to REST API in API Gateway. For straightforward Lambda proxy integrations, it is the recommended choice.
aws apigatewayv2 create-api \
--name hello-http-api \
--protocol-type HTTP \
--region us-east-1
Note the ApiId from the response — you will need it in every subsequent command. Store it in a shell variable to avoid copy-paste errors:
API_ID=$(aws apigatewayv2 create-api \
--name hello-http-api \
--protocol-type HTTP \
--region us-east-1 \
--query 'ApiId' \
--output text)
echo $API_ID
Step 3: Create the Lambda Integration
This step binds the API to a specific Lambda function. The IntegrationUri must be the full Lambda function ARN. The PayloadFormatVersion of 2.0 is the default for HTTP APIs and produces the simplified event structure.
INTEGRATION_ID=$(aws apigatewayv2 create-integration \
--api-id $API_ID \
--integration-type AWS_PROXY \
--integration-uri arn:aws:lambda:us-east-1:123456789012:function:hello-api \
--payload-format-version 2.0 \
--region us-east-1 \
--query 'IntegrationId' \
--output text)
echo $INTEGRATION_ID
Step 4: Create the GET Route
A route maps an HTTP method and path to an integration. The RouteKey format is METHOD /path. The Target must reference the integration using the integrations/ prefix followed by the integration ID.
aws apigatewayv2 create-route \
--api-id $API_ID \
--route-key 'GET /hello' \
--target integrations/$INTEGRATION_ID \
--region us-east-1
Step 5: Deploy to a Stage
Routes are not reachable until they are deployed to a stage. The $default stage is the conventional choice for HTTP APIs — it maps directly to the root of the invoke URL without a path prefix.
aws apigatewayv2 create-stage \
--api-id $API_ID \
--stage-name '$default' \
--auto-deploy \
--region us-east-1
The --auto-deploy flag means future route or integration changes are automatically deployed to this stage without a manual deployment step. This is convenient during development but consider disabling it for production stages where you want explicit deployment control.
Step 6: Grant API Gateway Permission to Invoke Lambda
This is the step most engineers skip on first attempt. API Gateway invokes Lambda using a service principal — it is not using your IAM credentials at runtime. Without a resource-based policy on the function, the invocation is denied and the route returns a 500.
Think of the Lambda resource-based policy as the function's doorbell list. API Gateway can knock all it wants, but if it's not on the list, the door stays shut — regardless of how correctly the integration is configured.
aws lambda add-permission \
--function-name hello-api \
--statement-id allow-apigw-invoke \
--action lambda:InvokeFunction \
--principal apigateway.amazonaws.com \
--source-arn arn:aws:execute-api:us-east-1:123456789012:$API_ID/*/*/hello \
--region us-east-1
The --source-arn follows the format arn:aws:execute-api:{region}:{account-id}:{api-id}/{stage}/{method}/{resource}. Using wildcards for stage and method (*/*/*) is acceptable during development. In production, scope the ARN to the specific stage and method to follow least privilege.
Step 7: Retrieve the Invoke URL and Test
Fetch the invoke URL from the API configuration:
aws apigatewayv2 get-api \
--api-id $API_ID \
--region us-east-1 \
--query 'ApiEndpoint' \
--output text
The endpoint follows the pattern https://{api-id}.execute-api.{region}.amazonaws.com. With the $default stage, the GET route is reachable at:
curl https://{api-id}.execute-api.us-east-1.amazonaws.com/hello
A successful response returns HTTP 200 with the JSON body your Lambda function returned.
Diagnosing the Most Common Failure: Silent 500 After Correct Setup
The symptom: the route exists, the integration is configured, the stage is deployed — and the endpoint still returns 500. The first instinct is to check the Lambda function code. That's usually wrong.
The actual cause in most cases is one of two things: the resource-based permission was never added (Step 6 was skipped), or the Lambda response format doesn't match what API Gateway expects for the payload format version in use.
For payload format version 2.0, Lambda must return an object with at minimum a statusCode integer field. If the function returns a raw string or an object without statusCode, API Gateway cannot parse the response and returns 502, not 500. The distinction matters for diagnosis.
Verify the resource-based policy is actually present on the function:
aws lambda get-policy \
--function-name hello-api \
--region us-east-1
If this command returns a ResourceNotFoundException, the permission was never added — that's your root cause. If the policy exists but the invocation still fails, check CloudWatch Logs for the Lambda function. A missing log group means the function was never invoked, pointing back to a permission or integration misconfiguration rather than a code error.
Resource Policy"} B -- "Policy missing" --> C["Run lambda:add-permission
Step 6"] B -- "Policy exists" --> D{"Check CloudWatch
Logs for function"} D -- "No log group" --> E["Lambda never invoked
Recheck integration + source-arn"] D -- "Logs present" --> F{"Error type?"} F -- "502" --> G["Response missing statusCode
Fix Lambda return object"] F -- "500" --> H["Runtime error in function
Fix application code"]
- 500 received — start at the permission layer, not the code layer.
- Check resource policy — if absent, add it with
lambda:add-permission. - Check CloudWatch Logs — no log group means Lambda was never invoked; a log group with errors means the function ran but failed.
- 502 (not 500) — Lambda ran but returned a malformed response; verify the response object includes
statusCode.
IAM Policy for the Lambda Execution Role
The Lambda execution role needs at minimum the ability to write logs. Without this, CloudWatch Logs will not capture invocation output, making debugging significantly harder.
🔽 Click to expand — Lambda execution role policy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:us-east-1:123456789012:log-group:/aws/lambda/hello-api:*"
}
]
}
How to Trigger Lambda from API Gateway: Wrap-Up and Next Steps
The six-step sequence — function, API, integration, route, stage, permission — is the complete minimum for a working HTTP API to Lambda connection. The permission step is non-negotiable and is the single most common omission in first attempts.
From here, consider:
- Adding a custom domain using API Gateway custom domain names and ACM certificates.
- Enabling JWT authorizers on the route to require authenticated requests.
- Configuring CORS on the API if the endpoint will be called from a browser.
- Reviewing the AWS HTTP API documentation for throttling, logging, and stage variable configuration: AWS HTTP API Developer Guide.
Glossary
| Term | Definition |
|---|---|
| HTTP API | A lightweight API Gateway API type optimized for Lambda proxy integrations and low latency, distinct from the older REST API type. |
| AWS_PROXY integration | An integration type where API Gateway passes the full request to Lambda and returns the function's response directly to the client without transformation. |
| Payload Format Version | Defines the shape of the JSON event object API Gateway sends to Lambda. Version 2.0 is the default for HTTP APIs. |
| Resource-based policy | A policy attached directly to a Lambda function that controls which principals (e.g., API Gateway) are allowed to invoke it. |
| $default stage | A special HTTP API stage that maps to the root of the invoke URL, eliminating the need for a stage path prefix. |
Comments
Post a Comment