micronaut-projects / micronaut-aws

Projects specific to integrating Micronaut and Amazon Web Services (AWS)
Apache License 2.0
82 stars 81 forks source link

Changed behaviour of routing evalution between Micronaut 3 and 4? #2078

Open dniel opened 3 months ago

dniel commented 3 months ago

Expected Behavior

In Micronaut 4 , when deploying application type lambda in the API Gateway, the API mapping in the gateway should be ignored, like it is in Micronaut 3.

Actual Behaviour

Its a REST API accessibly via AWS API Gateway under the api mapping /myapp and uses the Application type with io.micronaut.function.aws.proxy.payload1.ApiGatewayProxyRequestEventFunction routing in Micronaut to route to the correct @Controller in the lambda.

When testing this from postman to the api-gateway url, the request event looks like this Notice that the API Gateway has added the API mapping to the path property, but not to the resource property.

{
  "path": "/myapp/users",
  "resource": "/users",
  "httpMethod": "GET",
  "headers": {
    "Accept": "application/json"
  }
}

This works in Micronaut 3 using io.micronaut.function.aws.proxy.MicronautLambdaHandler because it seems like Micronaut 3 uses the "resource": "/users" property to evaluate the routing to correct method in the Controller.

When using Micronaut 3, I can change the API mapping of my Lambda in API Gateway to whatever I need and deploy the same lambda in different api endpoint, and it will still call my Users controller and return the expected response, because it use the "resource" property to route to map to the Users Controller, Micronaut 3 ignores the path the lambda is hosted on in the API Gateway.

The raw json event payload received by the Lambda looks like this

{
  "path": "/whatever/users",
  "resource":  "/users",
  "httpMethod": "GET",
  "headers": {
    "Accept": "application/json"
  }
}

Upgrading to Micronaut 4, this will break and return 404 instead.

In Micronaut 4 using the handler io.micronaut.function.aws.proxy.payload1.ApiGatewayProxyRequestEventFunction it seems like it has been changed which property in the request event that is evaluated for routing and its now the path-property instead, which by API Gateway includes the context-root set in the api mapping from Api Gateway, which means that the context root in the lambdas application.yml must now be set to the same.

A request as the one below will work in Micronaut 3, but not in Micronaut 4.

{
  "path": "/myapp/users",
  "resource": "/users",
  "httpMethod": "GET",
  "headers": {
    "Accept": "application/json"
  }
}

This means that the same lambda can't be used from different API Gatway APIs in Micronaut4 but could in Micronaut3.

Steps To Reproduce

Environment Information

Example Application

No response

Version

4.3.4

sdelamo commented 3 months ago

are you working with API Gateway Urls or with a custom domain? We have a dependency to help you work with API Gateway https://micronaut-projects.github.io/micronaut-aws/latest/guide/#amazonApiGateway

which I would recommend you to use instead of using context-page.

dniel commented 3 months ago

we use a custom domain with api mappings.

dniel commented 3 months ago

tested with the depcrecated "io.micronaut.function.aws.proxy.MicronautLambdaHandler" again, but it didn't change the outcome.

sdelamo commented 3 months ago

so, the issue is you use API Gateway with custom domain and you want also to use context-path and it does not work as expected?

dniel commented 3 months ago

so, the issue is you use API Gateway with custom domain and you want also to use context-path and it does not work as expected?

I absolutely don't want to configure context-path in my lambda, it breaks our code. :)

The issue is, in the Lambda event sent fromthe API Gateway.

{
  "path": "/whatever-api/users",
  "resource":  "/users",
  "httpMethod": "GET",
  "headers": {
    "Accept": "application/json"
  }
}

I want Micronaut to continue use the "resource"-property to evaluate routing so that its possible to add the lambda to whatever custom domain and api-mapping I want, as using "path" which contain the api-mapping from API Gateway "locks" the lambda to be used just in that API..

Reverting to the old behaviour of Micronaut3, with using the resource-property to route incoming request would is prefered and would make the lambda much more reusable between difference API Gateway apis.

sdelamo commented 3 months ago

do you have an example of how you are setting API Gateway in console or better in CDK code?

dniel commented 3 months ago

We are importing the openapi spec from micronaut to create the APIs. I will find an example.

This is how the OpenApi is generated from Micronaut, by adding Extensions for API- Gateway config to the source code.

  /users:
    get:
      operationId: getUsers
      responses:
        "200":
          description: Ok
          content:
            application/json: {}
      security:
      - cognito_auth:
        - https://services.xxxx/users
      x-amazon-apigateway-request-validator:
        x-amazon-apigateway-request-validator: "Validate body, query string parameters,\
          \ and headers"
      x-amazon-apigateway-integration:
        passthroughBehavior: when_no_match
        uri: "${lambda_rest_api_invoke_arn}"
        httpMethod: POST
        type: aws_proxy

Its imported by running terraform with the openapi spec as body, local.schema is just the open-api file.

resource "aws_api_gateway_rest_api" "api_gateway_rest_api" {
  description = "API for Users"
  name        = "users-rest-api"
  body        = local.schema
}

and in addition we create

This will create a api-gateway api https://www.exampe.com/myapp that listens for incoming users request on https://www.exampe.com/myapp/users and invoke our lambda on requests.

Events sent to the lambda will look like this

{
  "path": "/myapp/users",
  "resource":  "/users",
  "httpMethod": "GET",
  "headers": {
    "Accept": "application/json"
  }
}

It will work in Micronaut 3, but crash in Micronaut 4.

dniel commented 3 months ago

What class in Micronaut is parsing and handling the evaluation of the incoming Lambda event content? Especially where it reads the path and resource properties?

dniel commented 1 month ago

Seems like the change was done here https://github.com/micronaut-projects/micronaut-aws/blob/bb8410b025cd8b6a08d23000255379a5450e52f7/function-aws-api-proxy/src/main/java/io/micronaut/function/aws/proxy/payload1/ApiGatewayProxyServletRequest.java#L63