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

Websocket Route Not Working With Nested Router #4930

Closed
9 tasks done
uberbrodt opened this issue May 19, 2022 · 2 comments
Closed
9 tasks done

Websocket Route Not Working With Nested Router #4930

uberbrodt opened this issue May 19, 2022 · 2 comments
Labels
question Question or problem question-migrate

Comments

@uberbrodt
Copy link

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

from fastapi import APIRouter, FastAPI
from fastapi import WebSocket


router = APIRouter(prefix="/foo")
nested_router = APIRouter()
router.include_router(nested_router)
app = FastAPI()


# WORKS

# python -m websockets ws://localhost:8000/test-ws
@app.websocket("/test-ws")
async def test_ws(ws: WebSocket):
    await ws.accept()
    await ws.send_text("Hello World!")
    await ws.close()


# WORKS

# python -m websockets ws://localhost:8000/foo/test-ws
@router.websocket("/test-ws")
async def foo_test_ws(ws: WebSocket):
    await ws.accept()
    await ws.send_text("Hello World!")
    await ws.close()


# FAILS - 403 FORBIDDEN

# python -m websockets ws://localhost:8000/foo/bar/test-ws
@nested_router.websocket("/bar/test-ws")
async def bar_test_ws(ws: WebSocket):
    await ws.accept()
    await ws.send_text("Hello World!")
    await ws.close()


app.include_router(router)

Description

When upgrading from FastaAPI 0.72.0 to 0.78.0, noticed that a websocket path I had defined on a router included by another router was no longer available (server returns 403, trace logs indicate normal closure, think this is the normal behaviour when a websocket tries to upgrade a non-existent route).

Looks like #2640 fixed the case for a websocket defined on a router, but seems like the nested router makes this appear again.

Operating System

macOS

Operating System Details

Screen Shot 2022-05-19 at 10 47 43 AM

FastAPI Version

0.78.8

Python Version

3.10.1

Additional Context

It's kinda weird that it did work before, since #98 would indicate that it's been a long standing problem. 🤷

@uberbrodt uberbrodt added the question Question or problem label May 19, 2022
@uberbrodt
Copy link
Author

Alright so I pulled down the code and it seems like I can fix it with ordering the path definitions and the include_router. If I restructure the code like this:

from fastapi import APIRouter, FastAPI
from fastapi import WebSocket

nested_router = APIRouter()

# NOW WORKS 
# python -m websockets ws://localhost:8000/foo/bar/test-ws
@nested_router.websocket("/bar/test-ws")
async def bar_test_ws(ws: WebSocket):
    await ws.accept()
    await ws.send_text("Hello World!")
    await ws.close()

router = APIRouter(prefix="/foo")

# WORKS
# python -m websockets ws://localhost:8000/foo/test-ws
@router.websocket("/test-ws")
async def foo_test_ws(ws: WebSocket):
    await ws.accept()
    await ws.send_text("Hello World!")
    await ws.close()

router.include_router(nested_router)
app = FastAPI()

# WORKS
# python -m websockets ws://localhost:8000/test-ws
@app.websocket("/test-ws")
async def test_ws(ws: WebSocket):
    await ws.accept()
    await ws.send_text("Hello World!")
    await ws.close()

app.include_router(router)

I can then hit the nested router:

cbrodt@cbrodt-safely-you[fastapi]$  python -m websockets ws://localhost:8000/foo/bar/test-ws
Connected to ws://localhost:8000/foo/bar/test-ws.
< Hello World!
Connection closed: 1000 (OK).

So it seems like when calling include_router, it will miss any path operations not yet defined. Not sure on the right approach for a fix, but in the meantime maybe add a warning to the docs?

@qzcloveswcy
Copy link

Hello, I recently tried how to initiate a request to websocket in the sub-application, but found that the websocket parameter cannot be received in the sub-route. How to solve it?

@tiangolo tiangolo reopened this Feb 27, 2023
Repository owner locked and limited conversation to collaborators Feb 27, 2023
@tiangolo tiangolo converted this issue into discussion #6404 Feb 27, 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

3 participants