Java Serverless on AWS Lambda · Frameworks, Native Images and SDK Clients
API Gateway Events and Response Shapes in Java
Why a Java API returns 500 after switching from a REST API to an HTTP API, and how to handle event formats and binary bodies.
Scenario
Example app: a Java handler uses APIGatewayProxyRequestEvent (REST API, payload 1.0). The team switches the front door to an HTTP API to save cost and adds an endpoint that accepts image uploads.
What you see in production
After the switch, handlers see null HTTP methods and paths; the upload endpoint stores corrupted images that look like long base64 strings.
The naive code
public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent event, Context ctx) {
String method = event.getHttpMethod(); // null for HTTP API payload 2.0
byte[] image = event.getBody().getBytes(UTF_8); // body is base64 when isBase64Encoded is true
store(image);
return new APIGatewayProxyResponseEvent().withStatusCode(201);
}
Reproduce it
import java.nio.charset.StandardCharsets;
import java.util.*;
public class Main {
public static void main(String[] args) {
byte[] png = {(byte) 0x89, 'P', 'N', 'G', 13, 10, 26, 10}; // PNG signature
String body = Base64.getEncoder().encodeToString(png); // how API Gateway delivers binary
boolean isBase64Encoded = true;
byte[] naive = body.getBytes(StandardCharsets.UTF_8);
byte[] fixed = isBase64Encoded ? Base64.getDecoder().decode(body) : body.getBytes(StandardCharsets.UTF_8);
System.out.println("naive bytes: " + naive.length + " " + Arrays.toString(Arrays.copyOf(naive, 4)));
System.out.println("fixed bytes: " + fixed.length + " " + Arrays.toString(Arrays.copyOf(fixed, 4)) + " (valid PNG header: " + (fixed[1] == 'P') + ")");
}
}
Output
naive bytes: 12 [105, 86, 66, 79] fixed bytes: 8 [-119, 80, 78, 71] (valid PNG header: true)
Run this on your computer — see “Get Started” for setup.
Root cause
REST APIs send payload format 1.0 (APIGatewayProxyRequestEvent); HTTP APIs default to payload format 2.0 (APIGatewayV2HTTPEvent, method in requestContext.http.method, rawPath). Binary bodies arrive base64-encoded with isBase64Encoded = true, and responses with binary content must be base64-encoded too.
The fix
- Match the handler's input type to the integration:
APIGatewayV2HTTPEvent/APIGatewayV2HTTPResponsefor HTTP APIs and function URLs, or configure the HTTP API integration for payload 1.0 if you must keep the old types. - Decode bodies when
isBase64Encodedis true; for responses, setisBase64Encoded(true)and encode binary content. - Better for uploads: issue presigned S3 URLs so files never pass through Lambda (payload limits and cost).
public APIGatewayV2HTTPResponse handleRequest(APIGatewayV2HTTPEvent event, Context ctx) {
String method = event.getRequestContext().getHttp().getMethod();
byte[] body = event.getIsBase64Encoded()
? Base64.getDecoder().decode(event.getBody())
: event.getBody().getBytes(StandardCharsets.UTF_8);
// ...
return APIGatewayV2HTTPResponse.builder().withStatusCode(201).build();
}
Trade-offs
- Supporting both payload formats in one handler adds code; pick one per function.
- Proxying binary through Lambda is limited by payload size and costs duration; presigned URLs scale better.
- Frameworks (Serverless Java Container, Spring Cloud Function) hide the formats but add start-up cost.
Detect it in production
- Null fields after infrastructure changes; contract tests with sample events of each format.
- Stored files whose size is about 4/3 of the original (undecoded base64).
- 413 errors for large uploads.
Key points
- Payload 1.0 (REST API) and 2.0 (HTTP API, function URLs) need different event types.
- Decode base64 bodies; encode binary responses.
- Use presigned S3 URLs for uploads.
Further reading: HTTP API Lambda integrations and payload formats · aws-lambda-java-events on GitHub
Practice questions
Which Java event type should a handler behind an HTTP API use?
Answer
APIGatewayV2HTTPEvent with APIGatewayV2HTTPResponse, matching payload format 2.0 (also used by function URLs). REST APIs use APIGatewayProxyRequestEvent and APIGatewayProxyResponseEvent (payload 1.0).
Why might an uploaded image be stored corrupted by a Java Lambda function?
Answer
API Gateway delivers binary bodies base64-encoded with isBase64Encoded set to true; writing the body string's bytes stores the base64 text instead of the decoded binary.
What is a better way to handle large file uploads than sending them through Lambda?
Answer
Return a presigned S3 PUT URL so the client uploads directly to S3; process the file afterwards from an S3 event, avoiding payload limits and paying for upload time in Lambda.
Open in the app to mark lessons complete, take notes and track your progress.