Supply lambda context to Jersey resource

Viewed 753

I'm using aws-serverless-java-container to wrap a Jersey service in a AWS Lambda. I decided to use function alias to have a "test" and "prod" stage that eventually points to different versions of the lambda function.

I need to select some properties in a .properties file based on that alias, basically because I need to talk to a "test" or "prod" DB or use a different endpoint to invoke an external web service.

For such purpose I need to invoke the method getInvokedFunctionArn of the Context object. Unfortunately the Jersey resource is not aware of such context by default.

Below a sample resource:

@Path("/pet")
public class PetResource {

    @POST
    @Path("/")
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.WILDCARD)
    public Response createPet() {
        // how to call getInvokedFunctionArn from Lambda context object?
        return Response.status(200).entity("{'result': 'success'}").build();
    }
}

How can I enable the Jersey resource to have the invoked ARN? Can I inject it?

The lambda handler is defined as:

public class PetLambdaHandler implements RequestStreamHandler {

    private static final ResourceConfig jerseyApplication = new ResourceConfig().register(PetResource.class)
            .register(JacksonFeature.class);

    private static final JerseyLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler = JerseyLambdaContainerHandler
            .getAwsProxyHandler(jerseyApplication);

    @Override
    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
        handler.proxyStream(inputStream, outputStream, context);
    }
}
2 Answers

You cannot inject the Lambda context automatically. However, you can retrieve it form the ContainerRequestContext object. The serverless-java-container framework adds it as a request property.

You can probably do something like this (have not tested the code):

@GET
public String testLambdaContext(@Context ContainerRequestContext containerRequest) {
   Context lambdaContext =
       (Context) containerRequest.getProperty(RequestReader.LAMBDA_CONTEXT_PROPERTY);
   return lambdaContext.getInvokedFunctionArn()
}

You can Inject context to jersey resources using Spring profile

Define for test and prod profiles different methods/objects

If you don't have Spring, you can check jersey integration

jersey-spring4 module that will act as the integration bridge for Spring and Jersey.

See full example in github aws-serverless-java-container library running a Spring application with profiles in AWS Lambda

There are two ways to activate Spring Profiles (as defined with the @Profile annotation). We recommend using the static initializer that receives a list of profiles. The Serverless Java Container framework takes care of setting the profile and initializing the application at once.

public class StreamLambdaHandler implements RequestStreamHandler {
    private static SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
    static {
        try {
            AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
            applicationContext.register(PetStoreSpringAppConfig.class);
            handler = SpringLambdaContainerHandler.getAwsProxyHandler(applicationContext, "profile-1", "profile-2");
Related