in samcli/lib/providers/sam_api_provider.py [0:0]
def merge_routes(collector: ApiCollector) -> List[Route]:
"""
Quite often, an API is defined both in Implicit and Explicit Route definitions. In such cases, Implicit API
definition wins because that conveys clear intent that the API is backed by a function. This method will
merge two such list of routes with the right order of precedence. If a Path+Method combination is defined
in both the places, only one wins.
In a multi-stack situation, the API defined in the top level wins.
Parameters
----------
collector: samcli.lib.providers.api_collector.ApiCollector
Collector object that holds all the APIs specified in the template
Returns
-------
list of samcli.local.apigw.local_apigw_service.Route
List of routes obtained by combining both the input lists.
"""
implicit_routes = []
explicit_routes = []
# Store implicit and explicit APIs separately in order to merge them later in the correct order
# Implicit APIs are defined on a resource with logicalID ServerlessRestApi
for logical_id, apis in collector:
if logical_id in (SamApiProvider.IMPLICIT_API_RESOURCE_ID, SamApiProvider.IMPLICIT_HTTP_API_RESOURCE_ID):
implicit_routes.extend(apis)
else:
explicit_routes.extend(apis)
# We will use "path+method" combination as key to this dictionary and store the Api config for this combination.
# If an path+method combo already exists, then overwrite it if and only if this is an implicit API
all_routes: Dict[str, Route] = {}
# By adding implicit APIs to the end of the list, they will be iterated last. If a configuration was already
# written by explicit API, it will be overridden by implicit API, just by virtue of order of iteration.
# Within the explicit/implicit APIs, one defined in top level stack has the higher precedence. Here we
# use depth of stack_path to sort APIs (desc).
all_configs = sorted(explicit_routes, key=SamApiProvider._get_route_stack_depth, reverse=True) + sorted(
implicit_routes, key=SamApiProvider._get_route_stack_depth, reverse=True
)
for config in all_configs:
# Normalize the methods before de-duping to allow an ANY method in implicit API to override a regular HTTP
# method on explicit route.
for normalized_method in config.methods:
key = config.path + normalized_method
route = all_routes.get(key)
if route and route.payload_format_version and config.payload_format_version is None:
config.payload_format_version = route.payload_format_version
all_routes[key] = config
result = set(all_routes.values()) # Assign to a set() to de-dupe
LOG.debug(
"Removed duplicates from '%d' Explicit APIs and '%d' Implicit APIs to produce '%d' APIs",
len(explicit_routes),
len(implicit_routes),
len(result),
)
return list(result)