Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

Duplicated OperationID when adding route with multiple methods #4740

Closed
9 tasks done
bruchar1 opened this issue Mar 30, 2022 · 17 comments
Closed
9 tasks done

Duplicated OperationID when adding route with multiple methods #4740

bruchar1 opened this issue Mar 30, 2022 · 17 comments
Labels
question Question or problem question-migrate

Comments

@bruchar1
Copy link

bruchar1 commented Mar 30, 2022

First Check

  • I added a very descriptive title to this issue.
  • I used the GitHub search to find a similar issue and didn't find it.
  • I searched the FastAPI documentation, with the integrated search.
  • I already searched in Google "How to X in FastAPI" and didn't find any information.
  • I already read and followed all the tutorial in the docs and didn't find an answer.
  • I already checked if it is not related to FastAPI but to Pydantic.
  • I already checked if it is not related to FastAPI but to Swagger UI.
  • I already checked if it is not related to FastAPI but to ReDoc.

Commit to Help

  • I commit to help with one of those options 👆

Example Code

router.add_api_route(
    "/clear",
    clear,
    methods=["POST", "DELETE"]
)

Description

Seems to be caused by #4650.

The new generate_unique_id() function uses list(route.methods)[0].lower() as suffix for the operation_id. Therefore, in my example, both post and delete endpoints get _post suffix for operation_id, causing it to no longer be unique.

It then issues a "UserWarning: Duplicate Operation ID"

Operating System

Windows

Operating System Details

No response

FastAPI Version

0.75.0

Python Version

3.10.2

Additional Context

No response

@bruchar1 bruchar1 added the question Question or problem label Mar 30, 2022
@mbrav
Copy link

mbrav commented Apr 2, 2022

I am getting a similar problem. Am getting the following errors.

File "/fastapi/applications.py", line 216, in openapi
    return JSONResponse(self.openapi())
  File "/fastapi/applications.py", line 191, in openapi
    self.openapi_schema = get_openapi(
  File "/fastapi/openapi/utils.py", line 414, in get_openapi
    definitions = get_model_definitions(
  File "/fastapi/utils.py", line 35, in get_model_definitions
    model_name = model_name_map[model]

Upon further inspection of the code with the following lines:

flat_models = get_flat_models_from_routes(routes)
model_name_map = get_model_name_map(flat_models)
definitions = get_model_definitions(
    flat_models=flat_models, model_name_map=model_name_map
)

The problem is that basically that in my case, the variables passed into get_model_definitions() are flat_models where len(flat_models)=16 and model_name_map where len(flat_models)=15, hence the error. Here is a screen from debugger:

Screenshot_20220402_225519

So the problem in my case is that <class 'pydantic.main.Body_access_token_login_api_auth_token_post'> gets duplicated twice in flat_models and both for some reason seem to have the same hashes. For more info, it seems to be the fastapi.security.OAuth2PasswordRequestForm that is causing the trouble, but no sure.

Once I remove code with my auth endpoints, openapi schema gets generated and docs do not crash, but I get many instances of the following errors.

/fastapi/openapi/utils.py:183: UserWarning: Duplicate Operation ID tasks_list_api_tasks_get for function tasks_list at ./app/api/tasks.py
  warnings.warn(message)

My repo with the following problem is referenced above.

@mbrav
Copy link

mbrav commented Apr 2, 2022

Nevermind, found a solution. For future reference, the commit above fixed the issue. I was transferring some code from another project. Sorry if maybe not exactly relevant to the issue, but hope it helps someone in the future.

mbrav added a commit to mbrav/signup_api that referenced this issue Apr 5, 2022
mbrav added a commit to mbrav/signup_api that referenced this issue Apr 5, 2022
mbrav added a commit to mbrav/signup_api that referenced this issue Apr 5, 2022
mbrav added a commit to mbrav/signup_api that referenced this issue Apr 5, 2022
@jonatasoli
Copy link

@bruchar1 this solution above solve yout problem?

@bruchar1
Copy link
Author

No. @mbrav problem is unrelated to this.

@jonatasoli
Copy link

Nevermind, found a solution. For future reference, the commit above fixed the issue. I was transferring some code from another project. Sorry if maybe not exactly relevant to the issue, but hope it helps someone in the future.

@mbrav I believe this issue can be closed then :)

@mbrav
Copy link

mbrav commented May 2, 2022

@jonatasoli I agree, but I am not the one who opened it :)

@bruchar1
Copy link
Author

bruchar1 commented May 2, 2022

@jonatasoli Why do you want to close this? The bug is still there, and completely unrelated to @mbrav issue.

bruchar1 added a commit to bruchar1/fastapi that referenced this issue May 2, 2022
@bneijt
Copy link

bneijt commented Jun 8, 2022

There are multiple issues here:

  1. The APIRoute class generates the unique id but also supports multiple methods. This should only support a single method if it wants to use the method to generate a unique id (which to me seems like the only way to generate them, maybe a random uuid with proper seeding might also work, but that is probably hard to work with)
  2. The methods accessed by the generate_unique_id function are modeled as a set, which makes the order unpredictable. So the list(route.methods)[0] will result in different values for different runs, making the operationid unstable.

I'll create a quick MR to change the list to a sorted, but I think we should also change the APIRoute class to only accept a single method. Before going down that refactoring, I would like to see a response from any of the maintainers.

btw my current workaround is just splitting up the routes to different functions, so using routes.put and routes.delete decorators on the same method with the same arguments.

bneijt added a commit to bneijt/fastapi that referenced this issue Jun 8, 2022
The methods attribute accessed by the `generate_unique_id` function is modeled as a python set, which is not ordered and between runs might change. This results in the same fastapi generating different openapi specs if started multiple times.

This also relates to the bigger issue tiangolo#4740 but is not a solution for that issue.
bneijt added a commit to bneijt/fastapi that referenced this issue Jun 10, 2022
The methods attribute accessed by the `generate_unique_id` function is modeled as a python set, which is not ordered and between runs might change. This results in the same fastapi generating different openapi specs if started multiple times.

This also relates to the bigger issue tiangolo#4740 but is not a solution for that issue.
@stapetro
Copy link

Hello @bneijt, I confirm I hit the same issue with fastapi@0.79.1. I've decorated a method like this:

@router.api_route(
    "/example",
    methods=["POST", "PUT"],
    status_code=status.HTTP_201_CREATED,
)
async def save_example(...)
  pass

@462548187
Copy link

462548187 commented Dec 7, 2022

health_system.py

router = APIRouter(prefix="/system", route_class=ContextLogerRoute)

@router.get('/health', tags=['默认开启的健康检查'])
async def health_check():
"""
注册全局健康检查
:return:
"""
return Success(data='ok')

================
wanring: /Users/.../..../venv/lib/python3.11/site-packages/fastapi/openapi/utils.py:184: UserWarning: Duplicate Operation ID health_check_api_system_health_get for function health_check at /Users/.../..../fastApiFramework/app/routers/health/health_system.py
warnings.warn(message)

===================

How to solve this problem?

@stapetro
Copy link

stapetro commented Dec 7, 2022

@462548187 I suppose the warning comes from the /system route. You need to specify a particular method (a.k.a HTTP request method type). It has to work with the warning though.

@fulanii
Copy link

fulanii commented Dec 17, 2022

Similar problem : UserWarning: Duplicate Operation ID for all my routes

I'm getting this problem with all my routes, looked online and in documentation cant find a fix for it. Can anyone help solve this?

I have these methods and endpoints in my users.py
Screenshot 2022-12-17 at 5 52 35 PM

posts.py
Screenshot 2022-12-17 at 5 53 02 PM

and im getting this in the terminal
Screenshot 2022-12-17 at 5 55 35 PM

@ricardo-reis-1970
Copy link

Similar issue: UserWarning: Duplicate Operation ID

I've been reducing my example until all I have is this:

Freeze

fastapi==0.88.0
uvicorn==0.20.0
NOT using libs from global environment.

users.py

from fastapi import APIRouter

router = APIRouter()

@router.get("")
def users():
    return 1

__init__.py

# typical boilerplate

@app.get("/get_config")
def get_config():
    return cfg.properties

main.py

from <my_package> import app
...
app.include_router(users.router, prefix="/users", tags=["Users"])

With this, I get the warning:

[...].venv/lib/python3.10/site-packages/fastapi/openapi/utils.py:184: UserWarning: Duplicate Operation ID users_users_get for function users at [...]/<my_library>/routers/users.py
  warnings.warn(message)

Funny, though...

... when I take the endpoint from an app.route mount and paste it directly into __init__.py, like this:

app.get("/users")
def users():
    return 1

, just adjusting the endpoint, so that it is the same /users, no warning is issued!

What am I missing? Am I using app.include_router wrong? The API seems to work anyway, but some of us just don't like warnings, because those make us think we're not perfect.

@bkis
Copy link

bkis commented Jan 16, 2023

@ricardo-reis-1970 do you get these warnings only when running tests or also when running the app itself? Because for me it's only when running pytest. I haven't session-scoped my test_app or test_client fixtures so it's creating new instances with every test function (on purpose). Maybe that hints to the underlying issue?

@k-roychoudhury
Copy link

Just a thought: Can you or anyone facing the issue, confirm if you have included the router (with all routes) only once in the parent router or the fastapi app?
I was facing the same warning when I noticed I had added called app.include_router with the same router argument more than once. It resolved itself when I removed the extra call.

@bkis
Copy link

bkis commented Jan 18, 2023

@KRC1997 Yeah you're right (in a way). I only add the router once, but the problem occurred when I started using asgi-lifespan to include the startup- and shutdown routines (the app lifecycle) of my app when running tests. I had my test_app fixture not session-scoped but test-scoped (default) so it was re-initializing the app (including startup routines) for each and every test. But of course the actual app: FastAPI object was only imported once, so the startup routine was applied to the same app instance for every test. Now when you add the routers in that very startup routine, it will be added every time.

The following workaround fixed the problem for me and also fixed another issue I had anyway: I now still initialize the database client in the startup routine (and close it in the shutdown routine) but everything that belongs to initializing the actual app instance (e.g. registering routers), I moved to a pre_startup routine/function that just runs whenever the app module is loaded (on import):

def pre_startup_routine(app: FastAPI) -> None:
    # add middlewares
    ...

    # register routers
    ...

async def startup_routine() -> None:
    # init database client
    ...

async def shutdown_routine() -> None:
    # close database client and cleanup
    ...

# create FastAPI app instance
app = FastAPI(
    # ...
    on_startup=[startup_routine],
    on_shutdown=[shutdown_routine],
)

pre_startup_routine(app)

This has the additional advantage that it works well with my test setup.
If the reason for this warning is really only this mistake on the dev side, I guess this issue might also be closed as it's not really an issue with FastAPI but rather with how the app's lifecycle is handled in some situations.

@k-roychoudhury
Copy link

@bkis yeah, i do believe it has something to do with the lifecycle of the app: FastAPI object and associated dependencies. I don't think its a problem with FastAPI in general.

Repository owner locked and limited conversation to collaborators Feb 28, 2023
@tiangolo tiangolo converted this issue into discussion #8449 Feb 28, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
question Question or problem question-migrate
Projects
None yet
Development

No branches or pull requests