Lambda Proxy Integration vs. Standard Integration in API Gateway: A Deep Dive
When connecting AWS API Gateway to a Lambda function, the integration type you choose fundamentally changes what your Lambda receives, what it must return, and how much control API Gateway retains over the request/response lifecycle. Choosing the wrong type silently breaks your API or forces unnecessary boilerplate — understanding the difference is non-negotiable for production-grade serverless APIs.
TL;DR
| Dimension | Lambda Proxy Integration | Standard (Custom) Integration |
|---|---|---|
| Event format | Fixed, structured JSON envelope (headers, path, query, body, context) | Fully customizable via Velocity (VTL) mapping templates |
| Response format | Lambda MUST return a specific JSON structure | API Gateway transforms Lambda output via VTL before sending to client |
| Setup complexity | Low — zero mapping templates required | High — requires VTL templates for request and response |
| HTTP control | Lambda owns status code, headers, body | API Gateway owns status code mapping and header injection |
| Best for | REST APIs, microservices, rapid development | Legacy integrations, strict contract enforcement, payload transformation |
Architecture: How Each Integration Routes a Request
- Client Request: An HTTP request hits the API Gateway endpoint.
- Proxy path (top): API Gateway packages the entire request — method, headers, path parameters, query strings, body, and request context — into a single structured JSON event and forwards it verbatim to Lambda. No transformation occurs at the gateway layer.
- Standard path (bottom): API Gateway applies a VTL mapping template to reshape the incoming request before invoking Lambda. The Lambda receives only what the template explicitly extracts.
- Response path (Proxy): Lambda returns a structured JSON object; API Gateway passes it directly to the client with no modification.
- Response path (Standard): Lambda returns any shape; API Gateway applies a response mapping template and status code mapping before sending to the client.
Lambda Proxy Integration: The Event Object Anatomy
With proxy integration enabled, API Gateway constructs a deterministic event object. Every field is documented and predictable. Below is the canonical structure for a REST API (API Gateway v1):
🔽 [Click to expand] Full Proxy Integration Event Object (REST API / v1)
{
"resource": "/users/{userId}",
"path": "/users/42",
"httpMethod": "GET",
"headers": {
"Accept": "application/json",
"Authorization": "Bearer eyJ...",
"Host": "abc123.execute-api.us-east-1.amazonaws.com",
"X-Forwarded-For": "203.0.113.5"
},
"multiValueHeaders": {
"Accept": ["application/json"]
},
"queryStringParameters": {
"include": "profile"
},
"multiValueQueryStringParameters": {
"include": ["profile"]
},
"pathParameters": {
"userId": "42"
},
"stageVariables": {
"env": "prod"
},
"requestContext": {
"accountId": "123456789012",
"resourceId": "abc123",
"stage": "prod",
"requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef",
"identity": {
"sourceIp": "203.0.113.5",
"userAgent": "Mozilla/5.0"
},
"resourcePath": "/users/{userId}",
"httpMethod": "GET",
"apiId": "abc123"
},
"body": null,
"isBase64Encoded": false
}
Key Fields Explained
| Field | Type | Purpose |
|---|---|---|
httpMethod | String | HTTP verb (GET, POST, etc.) |
pathParameters | Map / null | Extracted path template variables |
queryStringParameters | Map / null | Single-value query params (last value wins for duplicates) |
multiValueQueryStringParameters | Map of lists / null | All values for duplicate query params |
headers | Map / null | Single-value HTTP headers |
body | String / null | Raw request body as a string (JSON must be parsed manually) |
isBase64Encoded | Boolean | True when binary payload is base64-encoded |
requestContext | Object | API Gateway metadata: stage, caller identity, request ID |
Required Lambda Response Format (Proxy Integration)
With proxy integration, Lambda must return this exact structure. Any deviation causes API Gateway to return a 502 Bad Gateway:
{
"statusCode": 200,
"headers": {
"Content-Type": "application/json",
"X-Custom-Header": "value"
},
"multiValueHeaders": {},
"body": "{\"userId\": 42, \"name\": \"Alice\"}",
"isBase64Encoded": false
}
Critical: body must be a string, not a JSON object. Serialize it with JSON.stringify() or equivalent before returning.
Standard (Custom) Integration: VTL-Driven Transformation
In standard integration, you author Velocity Template Language (VTL) mapping templates that define exactly what Lambda receives. This gives API Gateway full control over the contract.
🔽 [Click to expand] Example VTL Request Mapping Template
## Request mapping template (application/json)
{
"userId": "$input.params('userId')",
"queryParam": "$input.params('include')",
"authHeader": "$input.params('Authorization')",
"payload": $input.json('$')
}
Lambda receives only the fields the template extracts — nothing more. The event object shape is entirely under your control, which is powerful but requires discipline to maintain.
Standard Integration Response Flow
API Gateway maps Lambda's output back to HTTP using:
- Integration Response: Regex-matched on Lambda's error message to select a status code (e.g.,
.*Not Found.*→ 404). - Method Response: Defines the HTTP status codes the API officially exposes.
- Response Mapping Template: VTL that reshapes Lambda's return value into the final HTTP body.
HTTP API (v2) Proxy Integration: The Simplified Event Format
AWS API Gateway HTTP APIs (v2) use a different, leaner event format called payload format version 2.0. This is distinct from the REST API (v1) proxy event above.
🔽 [Click to expand] HTTP API v2 Payload Format 2.0 Event
{
"version": "2.0",
"routeKey": "GET /users/{userId}",
"rawPath": "/users/42",
"rawQueryString": "include=profile",
"headers": {
"accept": "application/json",
"authorization": "Bearer eyJ..."
},
"queryStringParameters": {
"include": "profile"
},
"pathParameters": {
"userId": "42"
},
"requestContext": {
"accountId": "123456789012",
"apiId": "abc123",
"http": {
"method": "GET",
"path": "/users/42",
"protocol": "HTTP/1.1",
"sourceIp": "203.0.113.5",
"userAgent": "Mozilla/5.0"
},
"requestId": "JKJaXmPLvHcESHA=",
"routeKey": "GET /users/{userId}",
"stage": "$default",
"time": "12/Mar/2020:19:03:58 +0000",
"timeEpoch": 1583348638390
},
"body": null,
"isBase64Encoded": false
}
v1 vs. v2 Payload Format: Key Differences
| Field | REST API (v1) | HTTP API (v2) |
|---|---|---|
| Version marker | None (implicit v1) | "version": "2.0" |
| HTTP method | httpMethod (top-level) | requestContext.http.method |
| Multi-value headers | Separate multiValueHeaders field | Comma-separated values in single headers map |
| Route info | resource field | routeKey field |
| Cookies | In headers | Separate top-level cookies array |
Decision Flow: Which Integration Should You Use?
Real-World Analogy
Think of API Gateway as a corporate mail room. With Proxy Integration, the mail room forwards the entire sealed envelope — stamp, return address, postmark, and all — directly to your desk. You open it and deal with everything yourself. With Standard Integration, the mail room opens the envelope, extracts only the relevant memo, reformats it onto a company letterhead, and then delivers it to you. On the way back out, they repackage your reply into the official corporate format before it leaves the building. More control, more process.
IAM & Security Considerations
Regardless of integration type, API Gateway requires permission to invoke your Lambda function. The resource-based policy on Lambda must grant lambda:InvokeFunction to the API Gateway service principal:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "apigateway.amazonaws.com"
},
"Action": "lambda:InvokeFunction",
"Resource": "arn:aws:lambda:us-east-1:123456789012:function:MyFunction",
"Condition": {
"ArnLike": {
"AWS:SourceArn": "arn:aws:execute-api:us-east-1:123456789012:abc123/*/GET/users/*"
}
}
}
]
}
The AWS:SourceArn condition scopes the permission to a specific API, stage, method, and resource path — following the principle of least privilege.
Common Pitfalls
- Forgetting to stringify the body: Returning a JSON object (not a string) in the
bodyfield of a proxy response causes a502. - Null vs. missing fields:
queryStringParametersisnull(not an empty object) when no query params are present. Always null-check before accessing keys. - Mixing v1 and v2 event shapes: If you migrate from REST API to HTTP API, your Lambda handler must be updated to read
requestContext.http.methodinstead of top-levelhttpMethod. - CORS with proxy integration: Lambda is responsible for returning CORS headers (e.g.,
Access-Control-Allow-Origin) in every response, including error responses.
Wrap-Up & Next Steps
For the vast majority of modern serverless APIs, Lambda Proxy Integration is the right default — it eliminates VTL complexity, gives Lambda full HTTP control, and aligns with how frameworks like AWS SAM, Serverless Framework, and CDK generate API Gateway resources by default. Reserve Standard Integration for scenarios requiring strict payload transformation at the gateway layer without burdening Lambda.
- 📖 AWS Docs: Set up Lambda proxy integrations
- 📖 AWS Docs: HTTP API Lambda integrations (payload format v2.0)
- 📖 AWS Docs: VTL Mapping Template Reference
Glossary
| Term | Definition |
|---|---|
| Proxy Integration | API Gateway passes the full HTTP request to Lambda as a structured event and returns Lambda's response directly to the client with no transformation. |
| Standard Integration | API Gateway applies VTL mapping templates to transform both the request (before Lambda) and the response (before the client). |
| VTL (Velocity Template Language) | A Java-based templating language used by API Gateway to define request/response mapping logic. |
| Payload Format Version | The schema version of the event object sent to Lambda — v1.0 for REST APIs, v2.0 for HTTP APIs. |
| 502 Bad Gateway | The HTTP error returned by API Gateway when Lambda's response does not conform to the expected proxy response structure. |
Comments
Post a Comment