8000 🐛 Fix `generate_unique_id` to produce consistent IDs for operations with multiple methods by mohiuddin-khan-shiam · Pull Request #13861 · fastapi/fastapi · GitHub
[go: up one dir, main page]

Skip to content

🐛 Fix generate_unique_id to produce consistent IDs for operations with multiple methods #13861

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

mohiuddin-khan-shiam
Copy link

Description

generate_unique_id picked list(route.methods)[0], which depends on the internal,
non-deterministic order of a set.
The resulting operationIds could oscillate between launches (e.g. get_items_get
vs get_items_post), breaking caches and client generation.

The fix sorts the HTTP methods first and then selects the first value, ensuring a
stable, predictable operationId across runs while preserving the original logic.

@YuriiMotov YuriiMotov added the bug Something isn't working label Jul 3, 2025
@YuriiMotov YuriiMotov changed the title Make generate_unique_id produce deterministic operation IDs 🐛 Fix generate_unique_id to produce consistent IDs for operations with multiple methods Jul 3, 2025
@YuriiMotov
Copy link
Contributor

@mohiuddin-khan-shiam, thanks for your interest in FastAPI!

I just found similar PR. It was rejected with the reason:

Using multiple methods for the same function is not actually supported. @router.api_route() is there as a semi-internal utility, and because Starlette supports multiple methods, the interface is there. But the official way to do it in FastAPI and have all the FastAPI features (including the automatic OpenAPI integration, with operation IDs) is by using the dedicated methods, like app.post(), app.get(), etc.

So, the proposed solution is to avoid using .api_route("/", methods=["PUT", "POST"]). Use multiple decorators with single methods instead:

@app.put("/")
@app.post("/")
async def po() -> MyModel:
    return {}

@Pavanmanikanta98
Copy link

Hi @tiangolo, @YuriiMotov ,

I've noticed that multiple users have created issues or PRs (like #4851 and #13861) related to using @app.api_route() or @router.api_route() with multiple HTTP methods (e.g., methods=["POST", "PUT"]). These lead to non-deterministic operationIds and confusion around FastAPI's expected routing behavior.

To help reduce future duplicates and improve the DX (developer experience), I'd like to propose adding a clear subsection in the documentation, either under:

  • "Path Operation Decorators" (most ideal),
  • or "Dependencies in Path Operation Decorators", if that's more appropriate.

This subsection would clarify that FastAPI does not officially support multiple HTTP methods on a single function, even if Starlette does. Instead, users should define each method with its own decorator.

For example:

❌ Don't do this:

@app.api_route("/items/", methods=["GET", "POST"])
async def get_or_create_item():
    ...

✅ Do this instead:

@app.get("/items/")
async def read_items():
    return [{"item_id": "Foo"}]

@app.post("/items/")
async def create_item():
    return {"item_id": "Foo", "status": "created"}

Even if both routes share logic, users can extract it into a helper function to stay consistent with FastAPI's OpenAPI handling.

Let me know if you're open to a PR for this! I’d be happy to contribute the exact wording and placement based on your preferences.

Thanks for the awesome framework 🙌

@YuriiMotov
Copy link
Contributor

@Pavanmanikanta98, I think we need such PR. I can't guarantee it will be merged, but I will support it.

Just one thing. I would implement the code example as one endpoint function with 2 path decorators.

@app.put("/")
@app.post("/")
async def po(request: Request):
    if reques.method == "PUT":
        # Do something
    else:
        # Do something else
    return {}

I would also add docstring to api_route method with the warning and the link to the docs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0