Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for API Gateway with a custom domain #16

Closed
drissamri opened this issue Mar 5, 2019 · 5 comments
Closed

Support for API Gateway with a custom domain #16

drissamri opened this issue Mar 5, 2019 · 5 comments
Assignees

Comments

@drissamri
Copy link

When using the API Gateway support added in micronaut-projects/micronaut-core#540 it works until you add a custom domain name to the API Gateway, then the Lambda is invoked but return a 404.

Steps to Reproduce

Not sure how I can add a easy to reproduce test case since some setup for the domain is needed.

  1. Create Micronaut app with AWS API Gateway support
  2. Create/use custom domain and add it to AWS API Gateway
  3. Call the custom domain name API URL

Expected Behaviour

Same output as the generated API Gateway URL should be given

Actual Behaviour

Tell us what happens instead

The Lambda is invoked but a HTTP 404 is generated.

  • There is some reference to this issue in the aws-serverless-java-container library: API Gateway Path Mapping Problem aws/serverless-java-container#112
  • @musketyr has already pointed out the same issue in his library: ttps://github.com/agorapulse/micronaut-libraries/blob/master/micronaut-function-aws-agp/src/main/groovy/com/agorapulse/micronaut/agp/ApiGatewayProxyHttpRequest.java#L203-L212

Environment Information

  • Operating System: AWS Lambda
  • Micronaut Version: 1.1.0.M2
  • JDK Version: 1.8
@graemerocher graemerocher transferred this issue from micronaut-projects/micronaut-core Mar 6, 2019
@graemerocher graemerocher self-assigned this Mar 12, 2019
@graemerocher
Copy link
Contributor

Can you provide an example of your API gateway request JSON when using a custom domain?

@musketyr
Copy link
Contributor

@graemerocher the main difference is the path in the request

{ "path" : "/v1/tokens", "requestContext": { "path" : "/v1/tokens" }

where /v1 is the stage prefix

@graemerocher
Copy link
Contributor

@musketyr So it is my understanding that is what the stripBasePath method is for which has to be configured by the user https://github.com/micronaut-projects/micronaut-aws/blob/master/function-aws-api-proxy/src/main/java/io/micronaut/function/aws/proxy/AbstractLambdaContainerHandler.java#L171

Or am I mistaken?

@musketyr
Copy link
Contributor

that could be one of the solutions but it would be better if the integration is able to determine it itself. the API can be in theory accessed in both ways - using the custom domain and using the original AWS native URL. here's a sample JSON:

{
    "resource": "/tokens",
    "path": "/develop/tokens",
    "httpMethod": "OPTIONS",
    "headers": {
        "Accept-Encoding": "gzip,deflate",
        "CloudFront-Forwarded-Proto": "https",
        "CloudFront-Is-Desktop-Viewer": "true",
        "CloudFront-Is-Mobile-Viewer": "false",
        "CloudFront-Is-SmartTV-Viewer": "false",
        "CloudFront-Is-Tablet-Viewer": "false",
        "CloudFront-Viewer-Country": "CZ",
        "Host": "identity.beta.agorapulse.com",
        "User-Agent": "Apache-HttpClient/4.5.6 (Java/1.8.0_152-release)",
        "Via": "1.1 1a25e657bbdfbe4dde177fef28655f03.cloudfront.net (CloudFront)",
        "X-Amz-Cf-Id": "X-zJ3VmbMC6-6OZ8gcluAt-UdTv9A2LOPbGHv2MbExwS1erLeMz42g==",
        "X-Amzn-Trace-Id": "Root=1-5c8a0953-6c76ce00130c0fc6daee7f1c",
        "X-Forwarded-For": "37.48.19.34, 70.132.52.87",
        "X-Forwarded-Port": "443",
        "X-Forwarded-Proto": "https"
    },
    "multiValueHeaders": {
        "Accept-Encoding": [
            "gzip,deflate"
        ],
        "CloudFront-Forwarded-Proto": [
            "https"
        ],
        "CloudFront-Is-Desktop-Viewer": [
            "true"
        ],
        "CloudFront-Is-Mobile-Viewer": [
            "false"
        ],
        "CloudFront-Is-SmartTV-Viewer": [
            "false"
        ],
        "CloudFront-Is-Tablet-Viewer": [
            "false"
        ],
        "CloudFront-Viewer-Country": [
            "CZ"
        ],
        "Host": [
            "identity.beta.agorapulse.com"
        ],
        "User-Agent": [
            "Apache-HttpClient/4.5.6 (Java/1.8.0_152-release)"
        ],
        "Via": [
            "1.1 1a25e657bbdfbe4dde177fef28655f03.cloudfront.net (CloudFront)"
        ],
        "X-Amz-Cf-Id": [
            "X-zJ3VmbMC6-6OZ8gcluAt-UdTv9A2LOPbGHv2MbExwS1erLeMz42g=="
        ],
        "X-Amzn-Trace-Id": [
            "Root=1-5c8a0953-6c76ce00130c0fc6daee7f1c"
        ],
        "X-Forwarded-For": [
            "37.48.19.34, 70.132.52.87"
        ],
        "X-Forwarded-Port": [
            "443"
        ],
        "X-Forwarded-Proto": [
            "https"
        ]
    },
    "queryStringParameters": null,
    "multiValueQueryStringParameters": null,
    "pathParameters": null,
    "stageVariables": {
        "lambdaAlias": "DEV"
    },
    "requestContext": {
        "resourceId": "984ifg",
        "resourcePath": "/tokens",
        "httpMethod": "OPTIONS",
        "extendedRequestId": "WhZlBFIsjoEFZhQ=",
        "requestTime": "14/Mar/2019:07:57:07 +0000",
        "path": "/develop/tokens",
        "accountId": "794392443626",
        "protocol": "HTTP/1.1",
        "stage": "develop",
        "domainPrefix": "identity",
        "requestTimeEpoch": 1552550227369,
        "requestId": "c37cda63-462e-11e9-8866-09654a81e41b",
        "identity": {
            "cognitoIdentityPoolId": null,
            "accountId": null,
            "cognitoIdentityId": null,
            "caller": null,
            "sourceIp": "37.48.19.34",
            "accessKey": null,
            "cognitoAuthenticationType": null,
            "cognitoAuthenticationProvider": null,
            "userArn": null,
            "userAgent": "Apache-HttpClient/4.5.6 (Java/1.8.0_152-release)",
            "user": null
        },
        "domainName": "identity.beta.agorapulse.com",
        "apiId": "j1gqf453fi"
    },
    "body": null,
    "isBase64Encoded": false
}

resource is actually the path you are looking for but it may contain variables, therefore I reconstruct the path from the resource and path variables

static String reconstructPath(String resource, Map<String, String> pathVariables) {
        if (pathVariables == null) {
            return resource;
        }
        String path = resource;
        for (Map.Entry<String, String> variable : pathVariables.entrySet()) {
            path = path.replaceAll("\\{" + Pattern.quote(variable.getKey()) +"\\+?}", variable.getValue());
        }
        return path;
}

@musketyr
Copy link
Contributor

musketyr commented Mar 14, 2019

FYI here's a sample request handler to inspect the request

public class RequestDump implements RequestHandler<Map, APIGatewayProxyResponseEvent> {

    @Override
    public APIGatewayProxyResponseEvent handleRequest(Map input, Context context) {
        try {
            return new APIGatewayProxyResponseEvent().withStatusCode(200).withBody(new ObjectMapper().writeValueAsString(input));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return new APIGatewayProxyResponseEvent().withStatusCode(500).withBody(e.toString());
        }
    }
}

my library uses com.amazonaws.services.lambda.runtime.events model instead of SAM libraries model.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants