FastAPI + mangum works well for single-backend API gateways, but for API gateways where different resources can point to different FastAPI applications in different stacks (a true "gateway") this can break pretty quickly. I think the logic for path and root_path variables in the ASGI scope object should be extensible by the user – right now, root_path is hardcoded to a blank string (which I do not think is correct according to the ASGI specification).
Consider an example:
/prod (stage name)
|--> /service_a
| |--> /{proxy+}
| | |--> ANY => proxy to FastAPI lambda application
|--> /service_b
| |--> /{proxy+}
| | |--> ANY => proxy to another FastAPI lambda application
For the FastAPI (mangum) applications to work in this setup, api_gateway_base_path in the handlers of each application must be hardcoded to exactly match /service_a and /service_b respectively (the resource names in API Gateway).
I do not think that this is a good practice, because this means that the lambda code needs to be aware of the value of the settings used in API Gateway (coupling?). This hurts the portability and "plug and play" functionality of API Gateway Integrations with lambda applications. It also means I am unable to use the same codebase to mount two separate copies of a service under two different service names within the same API gateway.
The good news is that theoretically speaking the application is able to infer what is the true root path of the application (either /prod or /prod/service_a or even just /service_a in the case of custom domain names) just through the event that API gateway passes (the requestContext key contains information such as stage name, domain name and resource name). The AWS documentation also recommends the use of stage variables (that are also passed to the proxy event object) for application configuration:
You can also use stage variables to pass configuration parameters to a Lambda function through your mapping templates. For example, you might want to reuse the same Lambda function for multiple stages in your API, but the function should read data from a different Amazon DynamoDB table depending on which stage is being called. In the mapping templates that generate the request for the Lambda function, you can use stage variables to pass the table name to Lambda.
I believe this concept can be extended to the root path resolution as well. Through the use of stage variables, the API gateway decides where the FastAPI application should be mounted; the application simply reads this information at invocation time.
Suggested Solution
Instead of hardcoding a blank string in root_path and stripping path using api_gateway_base_path, simply define methods that can be overridden by child classes:
Inside adapter.py, Mangum.__call__:
scope = {
"type": "http",
"http_version": "1.1",
"method": http_method,
"headers": [[k.encode(), v.encode()] for k, v in headers.items()],
"path": self.resolve_asgi_path(event, context),
"raw_path": self.resolve_asgi_raw_path(event, context),
"root_path": self.resolve_asgi_root_path(event, context),
"scheme": headers.get("x-forwarded-proto", "https"),
"query_string": query_string,
"server": server,
"client": client,
"asgi": {"version": "3.0"},
"aws.event": event,
"aws.context": context,
}
Mangum.resolve_asgi_path and the others can contain the default implementation of stripping path of api_gateway_base_path for backward compatibility, but the point here is to allow other clients to customise the resolution logic depending on their use case (single backend api gateway? multiple backend api gateway? with or without custom domains?) by extending the class and overriding these methods.
FastAPI + mangum works well for single-backend API gateways, but for API gateways where different resources can point to different FastAPI applications in different stacks (a true "gateway") this can break pretty quickly. I think the logic for
pathandroot_pathvariables in the ASGI scope object should be extensible by the user – right now,root_pathis hardcoded to a blank string (which I do not think is correct according to the ASGI specification).Consider an example:
For the FastAPI (mangum) applications to work in this setup,
api_gateway_base_pathin the handlers of each application must be hardcoded to exactly match/service_aand/service_brespectively (the resource names in API Gateway).I do not think that this is a good practice, because this means that the lambda code needs to be aware of the value of the settings used in API Gateway (coupling?). This hurts the portability and "plug and play" functionality of API Gateway Integrations with lambda applications. It also means I am unable to use the same codebase to mount two separate copies of a service under two different service names within the same API gateway.
The good news is that theoretically speaking the application is able to infer what is the true root path of the application (either
/prodor/prod/service_aor even just/service_ain the case of custom domain names) just through the event that API gateway passes (therequestContextkey contains information such as stage name, domain name and resource name). The AWS documentation also recommends the use of stage variables (that are also passed to the proxy event object) for application configuration:I believe this concept can be extended to the root path resolution as well. Through the use of stage variables, the API gateway decides where the FastAPI application should be mounted; the application simply reads this information at invocation time.
Suggested Solution
Instead of hardcoding a blank string in
root_pathand strippingpathusingapi_gateway_base_path, simply define methods that can be overridden by child classes:Inside
adapter.py,Mangum.__call__:Mangum.resolve_asgi_pathand the others can contain the default implementation of strippingpathofapi_gateway_base_pathfor backward compatibility, but the point here is to allow other clients to customise the resolution logic depending on their use case (single backend api gateway? multiple backend api gateway? with or without custom domains?) by extending the class and overriding these methods.