Browse Source

Fix unstable operation IDs for multi-method routes

Make generated operation IDs deterministic when a route is registered with
multiple HTTP methods. This avoids depending on set iteration order and adds
a regression test to keep the behavior stable.
pull/15227/head
esubaalew 4 months ago
parent
commit
abb4ef9284
  1. 2
      fastapi/utils.py
  2. 27
      tests/test_generate_unique_id_function.py

2
fastapi/utils.py

@ -96,7 +96,7 @@ def generate_unique_id(route: "APIRoute") -> str:
operation_id = f"{route.name}{route.path_format}"
operation_id = re.sub(r"\W", "_", operation_id)
assert route.methods
operation_id = f"{operation_id}_{list(route.methods)[0].lower()}"
operation_id = f"{operation_id}_{sorted(route.methods)[0].lower()}"
return operation_id

27
tests/test_generate_unique_id_function.py

@ -1,8 +1,10 @@
import warnings
from types import SimpleNamespace
from fastapi import APIRouter, FastAPI
from fastapi.routing import APIRoute
from fastapi.testclient import TestClient
from fastapi.utils import generate_unique_id
from inline_snapshot import snapshot
from pydantic import BaseModel
@ -29,6 +31,31 @@ class Message(BaseModel):
description: str
class MethodsSet(set[str]):
def __init__(self, values: set[str], iteration_order: list[str]) -> None:
super().__init__(values)
self.iteration_order = iteration_order
def __iter__(self):
return iter(self.iteration_order)
def test_generate_unique_id_with_multiple_methods_is_stable():
route_a = SimpleNamespace(
name="handler",
path_format="/items",
methods=MethodsSet({"POST", "DELETE"}, ["POST", "DELETE"]),
)
route_b = SimpleNamespace(
name="handler",
path_format="/items",
methods=MethodsSet({"POST", "DELETE"}, ["DELETE", "POST"]),
)
assert generate_unique_id(route_a) == "handler_items_delete"
assert generate_unique_id(route_a) == generate_unique_id(route_b)
def test_top_level_generate_unique_id():
app = FastAPI(generate_unique_id_function=custom_generate_unique_id)
router = APIRouter()

Loading…
Cancel
Save