Open iain-raidiam opened 4 years ago
I am currently looking for a way to access the context information of an Lambda HTTP Integration Request. There are currently a few model implementations available: https://github.com/quarkusio/quarkus/tree/master/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/model
Generally it might be reasonable to separate Context and Request. If you deal with the amazon-lambda-http extension, you do not need to explicitly deal with the AwsProxyRequest object itself. It will be handled by the following implementation and made available in your application implementation. https://github.com/quarkusio/quarkus/blob/master/extensions/amazon-lambda-http/runtime/src/main/java/io/quarkus/amazon/lambda/http/LambdaHttpHandler.java
You would then just implement your JAX-RS resources as usual:
@Path("/")
public class ApiResource {
@POST
public Response handlePostRequest(final MyRequestEntity myRequestEntity) {
//...
return Response.status(HttpStatus.SC_ACCEPTED).build();
}
}
Unfortunately I did not figure out how to access context information during the request processing.
There is also no current indication that it is even possible when using the JAX-RS integration.
Any reason why you cannot just use the Amazon Lambda extension where you have access to this?
Noted on the problem you've raised. Any interesting one. I couldn't discern a solution from the Micronaut code.
Maybe, but it's just a big maybe... @iain-raidiam is trying to use HTTP API instead of Rest API. If I'm right then the mapping is a little bit different.
From this AWS Doc: Working with AWS Lambda proxy integrations for HTTP APIs
{
version: '1.0',
resource: '/my/path',
path: '/my/path',
httpMethod: 'GET',
headers: {
'Header1': 'value1',
'Header2': 'value2'
},
multiValueHeaders: {
'Header1': [ 'value1' ],
'Header2': [ 'value1', 'value2' ]
},
queryStringParameters: { parameter1: 'value1', parameter2: 'value' },
multiValueQueryStringParameters: { parameter1: [ 'value1', 'value2' ], paramter2: [ 'value' ] },
requestContext: {
accountId: '123456789012',
apiId: 'id',
authorizer: { claims: null, scopes: null },
domainName: 'id.execute-api.us-east-1.amazonaws.com',
domainPrefix: 'id',
extendedRequestId: 'request-id',
httpMethod: 'GET',
identity: {
accessKey: null,
accountId: null,
caller: null,
cognitoAuthenticationProvider: null,
cognitoAuthenticationType: null,
cognitoIdentityId: null,
cognitoIdentityPoolId: null,
principalOrgId: null,
sourceIp: 'IP',
user: null,
userAgent: 'user-agent',
userArn: null
},
path: '/my/path',
protocol: 'HTTP/1.1',
requestId: 'id=',
requestTime: '04/Mar/2020:19:15:17 +0000',
requestTimeEpoch: 1583349317135,
resourceId: null,
resourcePath: '/my/path',
stage: '$default'
},
pathParameters: null,
stageVariables: null,
body: 'Hello from Lambda!',
isBase64Encoded: true
}
{
version: '2.0',
routeKey: '$default',
rawPath: '/my/path',
rawQueryString: 'parameter1=value1¶meter1=value2¶meter2=value',
cookies: [ 'cookie1', 'cookie2' ],
headers: {
'Header1': 'value1',
'Header2': 'value2'
},
queryStringParameters: { parameter1: 'value1,value2', parameter2: 'value' },
requestContext: {
accountId: '123456789012',
apiId: 'api-id',
authorizer: { jwt: {
claims: {'claim1': 'value1', 'claim2': 'value2'},
scopes: ['scope1', 'scope2']
}
},
domainName: 'id.execute-api.us-east-1.amazonaws.com',
domainPrefix: 'id',
http: {
method: 'POST',
path: '/my/path',
protocol: 'HTTP/1.1',
sourceIp: 'IP',
userAgent: 'agent'
},
requestId: 'id',
routeKey: '$default',
stage: '$default',
time: '12/Mar/2020:19:03:58 +0000',
timeEpoch: 1583348638390
},
body: 'Hello from Lambda',
pathParameters: {'parameter1': 'value1'},
isBase64Encoded: false,
stageVariables: {'stageVariable1': 'value1', 'stageVariable2': 'value2'}
}
Hope it helps a little.
Any ideas so far? I'm also using the JAX-RS handlers on AWS Lambda and I'd love to be able to check stuff from the Lambda execution context (request context, actually). I asked this also in Zulip and StackOverflow and nobody answered :(
Same question here, couldn't find any answer
@patriot1burke since you've been working on the 2.0 payload, maybe you know how it's possible to access the requestContext or other parts of the original API Gateway request? ? (stageVariables, requestContext, routeKey, ...)
requestContext: {
accountId: '123456789012',
apiId: 'api-id',
authorizer: { jwt: {
claims: {'claim1': 'value1', 'claim2': 'value2'},
scopes: ['scope1', 'scope2']
}
}
Is it the same way in JAXRS and Vert.x (which I am trying out right now)
If you are using master, then just use the JAX-RS @Context inject with what you want, i.e.
com.amazonaws.services.lambda.runtime.Context; APIGatewayV2HTTPEvent APIGatewayV2HTTPEvent.RequestContext
If you are using the currently released amazon-lambda-http extension, you can still inject aws Context, but the gateway requests are a custom quarkus class.
io.quarkus.amazon.lambda.http.model.AwsProxyRequest; io.quarkus.amazon.lambda.http.model.AwsProxyRequestContext;
This only works for JAX-RS though right? Is there any similar way for Quarkus Vert.x?
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-vertx-web</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-amazon-lambda-http</artifactId>
</dependency>
@Route(path = "/modes", methods = POST)
void getModes(RoutingContext context) throws IOException {
works with Vert.x Web, Servlet, JAX-RS, Funqy, anything that is based on Quarkus + Netty.
Oh, you mean, getting the context stuff. You can get it in a vertx handler but its a bit internal API and convoluted. getContextObjects is keyed by the lambda context classses.
MultiMap qheaders = routingContext.request().headers(); if (qheaders instanceof QuarkusHttpHeaders) { for (Map.Entry<Class<?>, Object> entry : ((QuarkusHttpHeaders) qheaders).getContextObjects().entrySet()) { } }
Ouch, is this worth a ticket or really how it should be exposed?
MultiMap headers = context.request().headers();
if(headers instanceof QuarkusHttpHeaders) {
Map<Class<?>, Object> contextObjects1 = ((QuarkusHttpHeaders) headers).getContextObjects();
contextObjects1.forEach((key, value) -> {
if(value instanceof AwsProxyRequestContext) {
// Key: "class io.quarkus.amazon.lambda.http.model.AwsProxyRequestContext"
System.out.println("Key: " + key);
System.out.println("Account: " + ((AwsProxyRequestContext) value).getAccountId());
}
if(value instanceof Context) {
// Key: "interface com.amazonaws.services.lambda.runtime.Context"
System.out.println("Key: " + key);
System.out.println("Function Name: " + ((Context) value).getFunctionName());
}
});
Another question would be, with a unit test (@Quarkus) how do you trigger this? Since even when posting a full AWS API Gateway event JSON this still doesn't get filled in, only when deployed?
The main reason why I'd choose for Vert.x over JAXRS because the cold starts seems quite a bit faster
Is there a way to inject AwsProxyRequestContext into a JAX-RS Filter?
Description We should be able to access the AwsProxyRequest object when usng the amazon-lambda-http extension. This could be to retrieve context information from a lambda authorizer https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-output.html or cognito https://aws.amazon.com/blogs/compute/authorizing-access-through-a-proxy-resource-to-amazon-api-gateway-and-aws-lambda-using-amazon-cognito-user-pools/
Implementation ideas Micronaut provides this by making the request available to the controllers https://github.com/micronaut-projects/micronaut-aws/blob/master/function-aws-api-proxy/src/test/java/io/micronaut/function/aws/proxy/EchoMicronautController.java#L164