serverless-java-container
serverless-java-container copied to clipboard
Provide several Custom Domains and base paths
- Framework version: 1.3.2
- Implementations: Jersey
I have several different systems running my serverless container:
-
API Gateway + Lambda with Custom Domain Name at
https://api.myproject.com/v1/users/12345
custom domain:api.myproject.com
base path:v1/users
-
API Gateway + Lambda with stage path (for testing development releases): https://ixov38idvk.execute-api.us-east-1.amazonaws.com/dev/users/12345 base path:
users
-
SAM Local at
http://127.0.0.1:3000/users/12345
base path:users
-
Local Tomcat instance for local testing base path:
users
So basically the base path changes from the production stage to all other deployments.
Could we then specify several base paths and the one that first matches is the one to be removed?
Also, I tried to return the URI of a created user with:
URI uriLocation = uriInfo.getAbsolutePathBuilder().path(newUserUuid.toString()).build();
return Response.created(uriLocation).build();
But since the service base path was stripped, I get an invalid URI instead, such as https://api.myproject.com/12345
, instead of https://api.myproject.com/v1/users/12345
Is it possible to re-inject the stripped path, so we can programatically get the full URI of the original HTTP Request?
I'll look into this and let you know here. In the meanwhile, why not load the base path from an environment variable in Lambda?
It's not a bad solution, I will try it for now, it's just that I am like a "one man startup" so I avoid as much as possible having to configure many different things on many different environments, as I tend to forget something on deployments, or having to mirror locally some cloud specific configuration.
Automation usually is a solution for those things, but automating everything doesn't help me much either unfortunately, because is just more things to maintain, debug, catch-up, learn, remember and etc. So the simpler and compatible, the better for my particular development needs.
I think that the problem is that somewhere the handler is using the path
to map to the java method but a much more resilient solution would be to use the resource
.
When using a custom domain I found that I needed to modify the handleRequest
method of my RequestStreamHandler
so that the resource
is use to overwrite the path
.
For all of the examples above (and all that I have tested) resource
remains /users
even when path
changes from /users
to /v1/users
@Override
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
throws IOException {
/*
The handler assigns requests to methods based on the Path and not the Resource. To
make the handler resilient to things like Custom domains in API gateway with potentially multiple
mappings I need to get the resource from the request and set that as the path
*/
AwsProxyRequest request = objectMapper.readValue(inputStream, AwsProxyRequest.class);
// set the path to be the resource
request.setPath( request.getResource() );
//write the request to an out stream
ByteArrayOutputStream out = new ByteArrayOutputStream();
objectMapper.writeValue(out, request);
//proxy the request (a new input stream is made from the modified output stream
handler.proxyStream(new ByteArrayInputStream(out.toByteArray()), outputStream, context);
}
The issue with resource
@markjschreiber is that it does not include the parameters. For example, for the /users/sapessi
request the resource in the proxy request object will be /users/{username}
if you have defined the username
to be a path variable. I haven't had time to look into this yet.
You're right. This is another attempt that better handles API gateway proxying and is better than what I previously had but may still not be the best solution:
@Override
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
throws IOException {
/*
The handler assigns requests to methods based on the Path and not the Resource. To
make the handler resilient to things like Custom domains in API gateway with potentially multiple
mappings I need to get the resource from the request and set that as the path
*/
AwsProxyRequest request = objectMapper.readValue(inputStream, AwsProxyRequest.class);
log.info("Request path: {}", request.getPath());
log.info("Request path parameters: {}", request.getPathParameters());
log.info("Requested resource: {}", request.getResource());
if(request.getResource().equals("/{proxy+}")){
//set the path to be the proxy path parameter
String param = request.getPathParameters().get("proxy");
request.setPath("/"+param);
} else {
// set the path to be the resource
request.setPath(request.getResource());
}
//write the request to an out stream
ByteArrayOutputStream out = new ByteArrayOutputStream();
objectMapper.writeValue(out, request);
inputStream = new ByteArrayInputStream(out.toByteArray());
//proxy the request (a new input stream is made from the modified output stream
handler.proxyStream(inputStream, outputStream, context);
}