Description
When processing an invocation from an HTTP API Gateway, the APIGatewayV2HTTPEvent
does not appear to deserialize nested objects. These objects are successfully deserialized when using Map<String,Object>
.
Note: this is different from #432, although may have the same root cause.
aws-lambda-java-core
version: 1.2.3
aws-lambda-java-events
version: 3.11.5
Java target version: 11
Java runtime version: 21
Runtime ARN: arn:aws:lambda:us-east-1::runtime:02ff9a81932ab0e699171762afcb5aa2f8c2524ac6e34498612b55defb9c2e7f
HTTP gateway configuration (extract from CloudFormation template):
APIGateway:
Type: "AWS::ApiGatewayV2::Api"
Properties:
Name: !Sub "${AWS::StackName}"
Description: "Invokes the bucket-listing Lambda"
ProtocolType: "HTTP"
APIGatewayGetRoute:
Type: "AWS::ApiGatewayV2::Route"
Properties:
ApiId: !Ref APIGateway
RouteKey: "GET /{proxy+}"
Target: !Sub "integrations/${APIGatewayLambdaIntegration}"
APIGatewayPutRoute:
Type: "AWS::ApiGatewayV2::Route"
Properties:
ApiId: !Ref APIGateway
RouteKey: "PUT /{proxy+}"
Target: !Sub "integrations/${APIGatewayLambdaIntegration}"
APIGatewayPostRoute:
Type: "AWS::ApiGatewayV2::Route"
Properties:
ApiId: !Ref APIGateway
RouteKey: "POST /"
Target: !Sub "integrations/${APIGatewayLambdaIntegration}"
APIGatewayLambdaIntegration:
Type: "AWS::ApiGatewayV2::Integration"
Properties:
ApiId: !Ref APIGateway
Description: "Handles all requests for API operations"
IntegrationMethod: "POST"
IntegrationType: "AWS_PROXY"
IntegrationUri: !Sub "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaFunction.Arn}/invocations"
PayloadFormatVersion: "1.0"
Invocation command:
curl -XPUT -d '{"foo": 123, "bar":456, "baz": [9, 8]}' 'https://redacted.execute-api.us-east-1.amazonaws.com/something'
Version 1: uses APIGatewayV2HTTPEvent
public class HttpGWLambda1
implements RequestHandler<APIGatewayV2HTTPEvent,APIGatewayV2HTTPResponse>
{
@Override
public APIGatewayV2HTTPResponse handleRequest(APIGatewayV2HTTPEvent event, Context context)
{
System.out.println(event);
System.out.println(event.getRequestContext().getHttp());
return APIGatewayV2HTTPResponse.builder()
.withStatusCode(200)
.withBody("Hello, world")
.build();
}
}
Output from first println()
, with account number and GW endpoint redacted, but no other formatting. Note the fields that show null
values:
APIGatewayV2HTTPEvent(version=1.0, routeKey=null, rawPath=null, rawQueryString=null, cookies=null, headers={Content-Length=38, Content-Type=application/x-www-form-urlencoded, Host=redacted.execute-api.us-east-1.amazonaws.com, User-Agent=curl/7.68.0, X-Amzn-Trace-Id=Root=1-662273ce-2b40f35d65612f3032a6ea11, X-Forwarded-For=173.49.152.157, X-Forwarded-Port=443, X-Forwarded-Proto=https, accept=*/*}, queryStringParameters=null, pathParameters={proxy=something}, stageVariables=null, body=eyJmb28iOiAxMjMsICJiYXIiOjQ1NiwgImJheiI6IFs5LCA4XX0=, isBase64Encoded=true, requestContext=APIGatewayV2HTTPEvent.RequestContext(routeKey=null, accountId=123456789012, stage=$default, apiId=redacted, domainName=redacted.execute-api.us-east-1.amazonaws.com, domainPrefix=redacted, time=null, timeEpoch=0, http=null, authorizer=null, requestId=WecIThGXIAMEbKQ=))
Output from second println()
(attempting to retrieve the HTTP invocation information) is null
.
Version 2: uses Map<String,Object>
public class HttpGWLambda2
implements RequestHandler<Map<String,Object>,APIGatewayV2HTTPResponse>
{
@Override
public APIGatewayV2HTTPResponse handleRequest(Map<String,Object> event, Context context)
{
System.out.println(event);
return APIGatewayV2HTTPResponse.builder()
.withStatusCode(200)
.withBody("Hello, world")
.build();
}
}
Output from this version (again, with identifying information redacted, but otherwise unchanged). Note that child objects are populated:
{version=1.0, resource=/{proxy+}, path=/something, httpMethod=PUT, headers={Content-Length=38, Content-Type=application/x-www-form-urlencoded, Host=redacted.execute-api.us-east-1.amazonaws.com, User-Agent=curl/7.68.0, X-Amzn-Trace-Id=Root=1-66227575-38824f105e19d3c407288d96, X-Forwarded-For=redacted, X-Forwarded-Port=443, X-Forwarded-Proto=https, accept=*/*}, multiValueHeaders={Content-Length=[38], Content-Type=[application/x-www-form-urlencoded], Host=[redacted.execute-api.us-east-1.amazonaws.com], User-Agent=[curl/7.68.0], X-Amzn-Trace-Id=[Root=1-66227575-38824f105e19d3c407288d96], X-Forwarded-For=[redacted], X-Forwarded-Port=[443], X-Forwarded-Proto=[https], accept=[*/*]}, queryStringParameters=null, multiValueQueryStringParameters=null, requestContext={accountId=123456789012, apiId=redacted, domainName=redacted.execute-api.us-east-1.amazonaws.com, domainPrefix=redacted, extendedRequestId=WedKcjkCIAMEb1Q=, httpMethod=PUT, identity={accessKey=null, accountId=null, caller=null, cognitoAmr=null, cognitoAuthenticationProvider=null, cognitoAuthenticationType=null, cognitoIdentityId=null, cognitoIdentityPoolId=null, principalOrgId=null, sourceIp=redacted, user=null, userAgent=curl/7.68.0, userArn=null}, path=/something, protocol=HTTP/1.1, requestId=WedKcjkCIAMEb1Q=, requestTime=19/Apr/2024:13:45:25 +0000, requestTimeEpoch=1713534325773, resourceId=PUT /{proxy+}, resourcePath=/{proxy+}, stage=$default}, pathParameters={proxy=something}, stageVariables=null, body=eyJmb28iOiAxMjMsICJiYXIiOjQ1NiwgImJheiI6IFs5LCA4XX0=, isBase64Encoded=true}