Skip to content
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 Routes Only Work on FastAPI, not APIRouter #98

Closed
iwoloschin opened this issue Mar 24, 2019 · 37 comments
Closed

Websocket Routes Only Work on FastAPI, not APIRouter #98

iwoloschin opened this issue Mar 24, 2019 · 37 comments
Labels
bug Something isn't working reviewed

Comments

@iwoloschin
Copy link

Describe the bug
Websocket routes appear to only work on the main FastAPI object, not on APIRouter objects. When the same function is copied from a FastAPI object to an APIRouter object instead of working properly it just throws a 403.

To Reproduce
Steps to reproduce the behavior:

  1. The following works as expected:
from fastapi import FastAPI
app = FastAPI()

@app.websocket_route("/hello")
async def hello(websocket):
    await websocket.accept()
    await websocket.send_text("Hello!")
    response = await websocket.receive_text()
    print(response)
    await websocket.close()
    print("Closed")
  1. Moving hello to an APIRouter fails:
# main.py
from fastapi import FastAPI
import other
app = FastAPI()
app.include_router(other.router)
# other.py
from fastapi import APIRouter
router = APIRouter()

@router.websocket_route("/routerhello")
async def hello(websocket):
    await websocket.accept()
    await websocket.send_text("Router Hello!")
    response = await websocket.receive_text()
    print(response)
    await websocket.close()
    print("Router Closed")

Expected behavior
I expect a websocket route to work on both a FastAPI and APIRouter object.

Screenshots
Not applicable.

Environment:

  • OS: macOS 10.14.3

  • FastAPI Version: 0.9.0

  • Python version, get it with: 3.7.2

Additional context
Testing websocket client side with websocat.

@iwoloschin iwoloschin added the bug Something isn't working label Mar 24, 2019
@tiangolo
Copy link
Member

Thanks for the report!

It was fixed by @euri10 in PR #100.

It is available in FastAPI verson 0.10.0. 🎉 🚀

@iwoloschin
Copy link
Author

Just tested it out! I'm impressed at how quickly that was fixed, thanks!

@tiangolo
Copy link
Member

Awesome! Kudos to @euri10 for his work 😀🍰🌮

Thanks @iwoloschin for reporting back and closing the issue.

@brunopcarv

This comment has been minimized.

@Kludex
Copy link
Member

Kludex commented Mar 6, 2021

@brunopcarv This is a 2 years old issue... You'll have better chances of getting help if you create a new one. 😗

@Udayaprasad
Copy link

Udayaprasad commented Jul 27, 2021

@euri10 @tiangolo

Looks like this bug again comes in the 0.67.0 - latest version. Could you please check once?

APIRouter prefix is not getting utilized in @router.websocket('/') endpoint definition. I am getting 403 error.

router = APIRouter(
    prefix="/substructures",
    tags=["Substructures"],
    responses={404: {"description": "Not found"}},
)

@router.websocket('/')
async def websocket_execute(websocket: WebSocket):
    ....

image

@ghost
Copy link

ghost commented Jul 30, 2021

@euri10 @tiangolo

Looks like this bug again comes in the 0.67.0 - latest version. Could you please check once?

APIRouter prefix is not getting utilized in @router.websocket('/') endpoint definition. I am getting 403 error.

router = APIRouter(
    prefix="/substructures",
    tags=["Substructures"],
    responses={404: {"description": "Not found"}},
)

@router.websocket('/')
async def websocket_execute(websocket: WebSocket):
    ....

image

the same bug is present in version 0.65.1

@usotsuki777
Copy link

usotsuki777 commented Aug 27, 2021

@euri10 @tiangolo
Looks like this bug again comes in the 0.67.0 - latest version. Could you please check once?
APIRouter prefix is not getting utilized in @router.websocket('/') endpoint definition. I am getting 403 error.

router = APIRouter(
    prefix="/substructures",
    tags=["Substructures"],
    responses={404: {"description": "Not found"}},
)

@router.websocket('/')
async def websocket_execute(websocket: WebSocket):
    ....

image

the same bug is present in version 0.65.1

I have same issue with API-Router. return 403 response .

  • python : 3.9.5
  • fast-api : 0.68.1
  • os : ubuntu 20.04

UPDATE

I was trying with another way. The Result is, it's working in app.mount() method.
A codes are below.

websocket method : ws.py

# ws.py
from fastapi import FastAPI, WebSocket
from fastapi.middleware.cors import CORSMiddleware

ws = FastAPI()

# Your CORS
ws.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# websocket
@ws.websocket("/")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()

    while True:
        data = await websocket.receive_text()
        await websocket.send_text(f"Message text was: {data}")

main file : main.py

import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

# import  ws.py for 'mounted'
from ws import ws

app = FastAPI()

# Your CORS
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# mount ws.py
app.mount("/ws", ws)

# ... your routes OR something ...


if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

I feel like, it's better way to use in app.mount() instead of APIRouter() in current time.

@farlabjavier
Copy link

same error in 0.68.1

@nanacnote
Copy link

nanacnote commented Sep 28, 2021

I have the same issue at the moment if i set the prefix param in APIRoute() and try to connect to said route it raises 403 however if i drop the prefix it connects successfully. Thank you.

server

router = APIRouter(prefix="/service", tags=["service"])

@router.websocket("/data/market")
async def market_data(websocket: WebSocket):
    await websocket.accept()
    while True:
        data = await websocket.receive_text()
        await websocket.send_text(f"Message text was: {data}")

client

const s = new WebSocket("ws://localhost:5000/service/data/market")  //---> not working 
const s = new WebSocket("ws://localhost:5000/data/market")  //--->  working

@mntolia
Copy link

mntolia commented Oct 19, 2021

I am also facing the exact same issue. I am getting a 403 error for websockets under routers with prefix. It works without the prefix.

marcost2 added a commit to Espolvoritas/BackEnd that referenced this issue Oct 19, 2021
* As seen in fastapi/fastapi#98 and fastapi/fastapi#2634 websocket does not currently inherit the route prefix correctly, as such patch it to keep the websocket consistent with the rest of the file
* Also move userID to path parameters since websockets dont support body parameters
marcost2 added a commit to Espolvoritas/BackEnd that referenced this issue Oct 23, 2021
* As seen in fastapi/fastapi#98 and fastapi/fastapi#2634 websocket does not currently inherit the route prefix correctly, as such patch it to keep the websocket consistent with the rest of the file
* Also move userID to path parameters since websockets dont support body parameters
@obrua
Copy link

obrua commented Oct 25, 2021

same error in 0.70.0

@XCanG
Copy link

XCanG commented Jan 25, 2022

Still getting this issue on fastapi==0.73.0.

@xiki808
Copy link

xiki808 commented Feb 6, 2022

Same issue as mentioned @nanacnote

@lokaimoma
Copy link

Same issue in fastapi==0.73.0
image

@fujiawei-dev
Copy link

Same issue in fastapi==0.74.0

@mosynaq
Copy link

mosynaq commented Mar 14, 2022

Applying (read monkey patching) this saved my day. Waiting for @tiangolo to accept this PR.

@dnilosek
Copy link

Running into same issue, can that fix be included soon?

@sandiandian
Copy link

Same issue in fastapi==0.75.1

@tiangolo
Copy link
Member

Hey all! Some of you might have been experiencing a similar issue related to APIRouters with prefix. That was reported here: #2639

It was fixed by @Kludex here: #2640

And that fix will be available in FastAPI version 0.75.2, released in a couple of hours. 🚀

@philipokiokio
Copy link
Contributor

philipokiokio commented May 4, 2022

Hi everyone thanks for the help and for fixing this issue.

Truthfully the WebSocket fix works in development (Uvicorn server), however, in production (Ubuntu environment) the websocket did not connect to the APIRouter specified.

For the WebSocket to connect I used the /ws (test.com/ws) rather than the route I specified (test.com/test/flow/ws).
I just wanted to bring that to everyone's notice.

@philipokiokio
Copy link
Contributor

Another thing I noticed is that the WebSocket does not reflect in the Docs. Although the OpenAPI doc added is the 3.0 version which should be able to document websocket endpoints.

@philipokiokio
Copy link
Contributor

@Kludex I don't get the reason you are sending emojis such as the down thumb and all. it's better to ignore than act funny.

@Kludex
Copy link
Member

Kludex commented May 5, 2022

I sent emojis to show how I feel about your comments. I didn't mean to offend you.

Let me explain why:

Truthfully the WebSocket fix works in development (Uvicorn server), however, in production (Ubuntu environment) the websocket did not connect to the APIRouter specified.

There can't be a possible scenario on which it has a different behavior depending on the environment (prod vs dev) because of this issue. It can be because of other factors, but not because of this one.

Another thing I noticed is that the WebSocket does not reflect in the Docs. Although the OpenAPI doc added is the 3.0 version which should be able to document websocket endpoints.

This comment is not true. OpenAPI docs doesn't support WebSockets. On OpenAPI 3.1 Webhooks were added, but there was never support for WebSockets. AsyncAPI is an alternative for WebSockets, but FastAPI doesn't support it.

In any case, it's always better to open a new issue than engaging on a closed issue. It avoids users to believe the issue was wrongly closed.

@philipokiokio
Copy link
Contributor

@Kludex Thanks for your explanation.

To be fair I was not even pointing to this issue, and I agree that it could be something else. I was just bringing it forward (hoping) someone had experienced that and there is a fix to it.

With regards to OpenAPI documentation, thank you for clarifying that, I read it somewhere and I believed it (I also saw the OpenAPI swagger package on PyPI that suggested something along that line).

Thank you for your reply and all you do in the FastAPI community.

Continue to have an awesome day.

@Hyperx837
Copy link

same issue in fastapi==0.79.0

@philipokiokio
Copy link
Contributor

Hey @Hyperx837 yeah. You should consider creating another instance of the FastAPI application, create a WebSocket with the newly created app instance and then mount it on the Base App where the core application routers live.

@hscspring
Copy link

hscspring commented Dec 6, 2022

same issue in fastapi==0.88.0

i should use FastAPI instead of APIRouter....


update

ok, it works, well in two files.

If all in one file, should like this order:

router = APIRouter(prefix="/ws")

@router.websocket("/asr")
async def websocket_a(ws_a: WebSocket):...

app = FastAPI()
app.include_router(router)

not this:

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


@router.websocket("/asr")
async def websocket_a(ws_a: WebSocket):...

@Hyperx837 u could have a try

@tiangolo tiangolo changed the title [BUG] Websocket Routes Only Work on FastAPI, not APIRouter Websocket Routes Only Work on FastAPI, not APIRouter Feb 24, 2023
@Lopofsky
Copy link

Lopofsky commented May 27, 2023

@hscspring thank you so much for your clear reply!

That was the solution for me: replaced @router.websocket_route with @router.websocket then added a prefix to the APIRouter object and ws worked again.

@papapumpnz
Copy link

@Lopofsky what FastAPI version are you using? This is not working for me with 0.97.0. Getting the 403 error with websocket endpoints defined in other routes files. Using @router.websocket as well.

@Lopofsky
Copy link

@papapumpnz fastapi==0.95.2

@usenet506
Copy link

after update 0.95 to 0.100.1, I fix this problem

@AntonOfTheWoods
Copy link

AntonOfTheWoods commented Aug 8, 2023

I'm still getting this with 0.101.0. Everything works if I app.add_websocket_route("/api/v1/ws/ws", chatroom_ws) but not if I add with a router

@lewisjr
Copy link

lewisjr commented Aug 22, 2023

I confirm with @AntonOfTheWoods . Currently (22 Aug 2023 at 17:20 UTC) the latest version of FastAPI is 0.101.1 which is the version I am using. I updated from 0.97.1 which I was using where I was not able to add a websocket via router. Here is how I have it working in v0.101.1 (barebones):

old code

chat_ws.py

from fastapi import APIRouter, WebSocket

chat_socket = APIRouter()

@chat_socket .websocket("/chat")
async def handle_ws(ws: WebSocket):
    await ws.accept()

    while True:
        string = await ws.receive_text()
        await websocket.send_text(string)

main.py

from fastapi import FastAPI
from . import chat_socket

app = FastAPI()

app.add_websocket_route("/ws", chat_socket)

Edit

Turns out my previous code was wrong, the prefix has to be the same on both the include statement and in the router code. This is for v0.101.0 - v0.101.1. Furthermore, you cannot have route params for this implementation, it will not recognise the route and give you a 403 Error. That being said, if you want to split your websocket code into different modules and have no need to use route params, the working version of it is below:

chat_ws.py

from fastapi import APIRouter, WebSocket

chat_socket = APIRouter()

@chat_socket .websocket("/chat")
async def handle_ws(ws: WebSocket):
    await ws.accept()

    while True:
        string = await ws.receive_text()
        await websocket.send_text(string)

main.py

from fastapi import FastAPI
from . import chat_socket

app = FastAPI()

app.add_websocket_route("/chat", chat_socket)

@annisat
Copy link

annisat commented Oct 12, 2023

Reporting this issue with version==0.103.2.
Following @lewisjr 's instruction I changed the route to the same. But postman still says it cannot connect to the url.
Sorry, false alarm. I wrapped another route prefix and I didn't notice it.

@AleksaMCode
Copy link

I had the same error when using Python v3.10.7 with FastAPI v0.104.1. Replacing @router.websocket_route with @router.websocket fixed the issue for me. Here is a sample code that works:

  • websocket method in ws/ws.py
from fastapi import WebSocket, APIRouter

router = APIRouter(
    prefix="/ws"
)

@router.websocket("/pub/{channel_id}")
async def ws_endpoint(websocket: WebSocket):
    # ...
  • main
import uvicorn
from fastapi import FastAPI
from ws import ws

app = FastAPI()
app.include_router(ws.router)

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

@fastapi fastapi locked as resolved and limited conversation to collaborators Dec 15, 2023
@Kludex
Copy link
Member

Kludex commented Dec 15, 2023

This was solved years ago, if you encounter a similar issue, please open a discussion.

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

No branches or pull requests