From 8c15509fc6fcfad2828f6ad58f4cae5b74199015 Mon Sep 17 00:00:00 2001 From: wwenrr Date: Wed, 1 Apr 2026 10:37:02 +0000 Subject: [PATCH] fix: make generated operation id method suffix deterministic --- fastapi/utils.py | 2 +- tests/test_generate_unique_id_function.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/fastapi/utils.py b/fastapi/utils.py index 12eaa2bf08..9a8683e081 100644 --- a/fastapi/utils.py +++ b/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 diff --git a/tests/test_generate_unique_id_function.py b/tests/test_generate_unique_id_function.py index c56e6d5794..8a1763befb 100644 --- a/tests/test_generate_unique_id_function.py +++ b/tests/test_generate_unique_id_function.py @@ -3,6 +3,7 @@ import warnings 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 @@ -1697,3 +1698,19 @@ def test_warn_duplicate_operation_id(): ] assert len(duplicate_warnings) > 0 assert "Duplicate Operation ID" in str(duplicate_warnings[0].message) + + +def test_generate_unique_id_with_multiple_methods_is_deterministic(): + app = FastAPI() + + @app.api_route("/items", methods=["POST", "DELETE"]) + def items(): + return {} # pragma: nocover + + route = next( + route + for route in app.routes + if isinstance(route, APIRoute) and route.path == "/items" + ) + + assert generate_unique_id(route) == "items_items_delete"