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
Use of socket.io #129
Comments
Socket-IO has an ASGI compatible app: https://python-socketio.readthedocs.io/en/latest/server.html#uvicorn-daphne-and-other-asgi-servers You should be able to mount that app like if it was a FastAPI sub-application: https://fastapi.tiangolo.com/tutorial/sub-applications-proxy/#mount-the-sub-application |
Hi, Also have a question regarding python-socketio, Ive tried:
Which does indeed seem to work, but only partially. Only GET requests seems to get through
Is there a way to also allow POST on Thanks |
I am unable to get this to work at all, even with the snippet above. |
I see, here is my complete example,
Where the
I then run uvicorn with the It seems that the routing mechanism in either FastAPI ot Starlette somehow only allows GET requests, but I might be wrong and I'm maybe doing something else wrong. @BlackHoleFox: it did not work at all for me either until I noticed that second parameter of |
Finally, sio = socketio.AsyncServer(async_mode='asgi')
sio_asgi_app = socketio.ASGIApp(sio, app, socketio_path="/api/socket.io")
sio.register_namespace(ws.ConnectNS('/')) Works just fine if you use the |
@marcus-oscarsson I ended up with the same results. I can directly use the |
@BlackHoleFox I see, I simply removed the |
So are we giving up on |
@kientt86 I would say that its up to the maintainer, @tiangolo, to decide exactly what to do with app.mount. I'm not sure if I used it correctly in my example so it could also simply be that I'm missing some option. It would be nice if it worked with Using the |
Thanks for all the reports guys. I want to check how to integrate Socket.IO and integrate it directly in the docs, I haven't had the time though, but I'll do it hopefully soon. |
I´m looking forward for this integrate. It would be great for the project. cheers! |
This is more of a feature request but related to using Hoping this can be implemented on top of the general |
I'm struggling with getting this to work with FastAPI. I've tried this code: fast_app = FastAPI(
openapi_url='/api/notifications/openapi.json',
docs_url='/api/notifications/docs',
redoc_url='/api/notifications/redoc'
)
sio = socketio.AsyncServer(
async_mode='asgi',
cors_allowed_origins='*'
)
app = socketio.ASGIApp(
socketio_server=sio,
other_asgi_app=fast_app,
socketio_path='/api/notifications/socket.io/'
) Which allows me to connect to the socket.io endpoint, but when I attempt to connect to a FastAPI defined endpoint, it'll raise a traceback from python-engineio:
As best I can tell, engineio is attempting to call FastAPI with 4 parameters ('self', 'scope', 'receive', and 'send') .. while 0.33 version of FastAPI is simply using the Starlette call method that only accepts ('self' and 'scope'). I'm interested to learn what version other people (@marcus-oscarsson ) are using where this works inside FastAPI app. I've managed to hack around it with this helper class: from fastapi import FastAPI
from starlette.types import ASGIInstance, Scope, Receive, Send
class FastAPISocketIO(FastAPI):
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> ASGIInstance:
fn = super(FastAPISocketIO, self).__call__(scope=scope)
return await fn(receive=receive, send=send) But it seems the problem is an incompatibility with Starlette and python-socketio? |
Turns out my problem was with Starlette. Starlette version 0.11.1 needed the above hack, while version 0.12.0 doesn't have the problem and works without the above hack. |
A bit more complete example, based on @szelenka's work that might help other people.
|
Any news? I look forward to it working. |
@mjmare Very good... that's works perfectly using uvicorn. But with gunicorn WSGI got some errors:
After some testing, I'm using this code: app = FastAPI(
title=config.PROJECT_NAME,
description=config.PROJECT_NAME,
version=config.PROJECT_VERSION,
debug=True
)
sio = socketio.AsyncServer(
async_mode='asgi',
cors_allowed_origins=','.join(config.ALLOW_ORIGIN)
)
sio_asgi_app = socketio.ASGIApp(
socketio_server=sio,
other_asgi_app=app
)
app.add_route("/socket.io/", route=sio_asgi_app, methods=['GET', 'POST'])
app.add_websocket_route("/socket.io/", sio_asgi_app) kind off working with gunicorn... sometimes, got the error above... I will keep trying and let you guys know... Cheers |
Can anyone provide some insight into whether they've gotten this to work well with a synchronous database connection (I'm using SQLAlchemy ORM) and what it takes to ensure thread-safety? |
I'm receiving the same error with running using Gunicorn. Running with Uvicorn doesn't get me the same response. |
I'm struggling with the same problem :( If I have 4 workers ( |
Has there been any update on this? Still struggling to find a complete working example. Thanks. |
There are a lot of different pieces in play here (gunicorn, uvicorn, starlette, fastapi, socket.io, python, ...), each of which is potentially relevant to figuring out if there is a problem. My strong suspicion is that this issue is not specific to FastAPI, but rather is a problem with uvicorn or starlette. It's probably worth trying to replicate the problem using just starlette and/or creating an issue in the starlette repo asking for guidance. At any rate, if you are having an issue and want help, please post the versions of each of the various dependencies you are using. That may not be enough to help resolve the issue, but as things stand it's basically impossible to help without knowing more. |
I had the same problem using the given example so I started from the python-socketio asgi example and added fastapi and it works 🎉 I upgraded a few packages compared to the example and here is my
And then the code is the example #!/usr/bin/env python
import socketio
from fastapi import FastAPI
app = FastAPI()
sio = socketio.AsyncServer(async_mode='asgi')
socket_app = socketio.ASGIApp(sio, static_files={'/': 'app.html'})
background_task_started = False
async def background_task():
<... EXACTLY LIKE app.py IN python-socketio/examples/server/asgi ...>
@sio.on('disconnect')
def test_disconnect(sid):
print('Client disconnected')
@app.get("/hello")
async def root():
return {"message": "Hello World"}
app.mount('/', socket_app) Then used |
This example works perfectly! Thank you boss. |
Hello I m trying to mount the socketio as a sub application on top of a Fast API app, and it doesn't seem to work. Although if I dont mount it and run as a separate application it is just fine. Can some one comment on it? Have you faced the same issue before? Here is my code.
Client:
Error I get on Server side:
Here is the error I get on client side:
|
I produced a complete example with unit tests in this comment of issue miguelgrinberg/python-socketio#332, although it doesn't use import pytest
from test.utils import UvicornTestServer
@pytest.fixture
async def start_stop_server():
"""Start server as test fixture and tear down after test"""
server = UvicornTestServer() # use 'port' kwarg to set alternative port, default is 8000
await server.up()
yield
await server.down()
@pytest.mark.asyncio
async def test_method1(start_stop_server):
"""A simple http test"""
# your test goes here
# the gotcha here is that you can't use request.get, because it would block
import aiohttp
async with aiohttp.ClientSession() as session:
async with session.get('http://localhost:8000/mytest') as response:
assert response.status == 200
content = await response.text()
assert 'my test' in content
|
TL;DR paths are important, beware of mounting it in Mounting it outside of sio = socketio.AsyncServer(async_mode='asgi', cors_allowed_origins="*")
app.mount("/ws", socketio.ASGIApp(sio)) Will yield a connection in Problems may arise if you have any kind of rules/middleware/etc. that apply to |
EVENT 1: (if other_asgi_app arg)
The Server raise an exception: <Current thread 0x00007fc4bab0d280 (most recent call first):>
|
@includeamin I tried the simple example you provided but I get |
did you run exactly my sample code? |
Oh, whoops, yeah you're right, there were a few problems I figured out:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade"; |
@dmontagu exactly. I had the same problems, but then I tried to get all the dependencies with versions provided by @hillairet. Finally, it's working now, huh... |
Hello, I am trying to write unittests for socketio, I tried every solution here and nothing works, generally python client cannot connect to server.
Generally running connect connects to app
but it looks like it connects to another app, cause User connected is not printed and emiting raises Edit: |
I couldn't find that information anywhere: |
I have integrated socketio with the fastapi core. pip install "fastapi[socketio] @ git+https://github.com/bnnk/fastapi" Then, after installation, to use: from fastapi.websocketio import SocketIOMerger
<... code here ...>
app = SocketIOMerger(app, <... socketio instance variable ...>) |
i get recursion error as soon as i do |
I got this implemented like this. |
Will it be merged with core?? |
@includeamin Thanks for solution, I have to correct js client for newer versions: (for python-socketio = 5.x and js socketio=4.x) <script>
socket = io('http://localhost:3001', { // <- url parameter is not 'http://localhost:3001/ws'
path: '/ws/socket.io'
});
</script> Otherwise, client thinks /ws is a namespace and altough connection is succesful, server side does not respond to client requests, since namespace doesn't exist on the server side. For custom namespaces : <script>
socket = io('http://localhost:3001/GreyRook', { // <-to connect GreyRook namespace
path: '/ws/socket.io'
});
</script> |
can anybody say any simple implementation of fastApi (uvicorn server ) with simple python client . |
Do you know how to add Fastapi Dependencies on socketio endpoints similar to default Fastapi websockets? |
This one should works for you. |
You could check this one integrated into authx |
Thanks @kosciej16 @yezz123 I am going to check your links |
Hey, I dont get it working with the URL path and I dont know why. There is always the Thanks for you help in advanced So this is my code in a nutshell: socket_server.py # File socket_server.py
import socketio
sio = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*")
asgi = socketio.ASGIApp(sio)
@sio.on("connect")
def connect(sid, environ, auth) -> None:
print(f"Socket connected: {sid}") application.py (mount at the bottom) # File application.py where you get the FastAPI app
from sockets.socket_server import asgi
def get_app() -> FastAPI:
app = FastAPI(
docs_url="/api/docs",
redoc_url="/api/redoc",
openapi_url="/api/openapi.json",
default_response_class=UJSONResponse,
)
# Disable Docs
if settings.environment != "dev":
app.openapi_url = None
# Adds startup and shutdown events.
register_startup_event(app) # Just create folders if not exist
register_shutdown_event(app)
# Main router for the API.
app.include_router(router=api_router, prefix="/api")
# add static files
app.mount("/static", StaticFiles(directory="/static"), name="static")
app.mount("/", StaticFiles(directory="/pages"), name="pages")
# add websocket
app.mount("/ws", asgi, name="socket")
return app JS const socket = io.connect('http://' + document.domain + ':' + location.port, {
path: '/ws/socket.io'
}); And this is my error:
Client:
Versions I use:
|
Hello @Floskinner you can try with this configuration at client side.
|
Hello @jonra1993 thanks for your help! I got it woking now :) ...but I also got another error and if anyone gets the same error, here is my solution / hint: Error message:
With loguru i can see
Solution:I also have to change the order of my route mounts: # Main router for the API.
app.include_router(router=api_router, prefix="/api")
# add static files
app.mount("/static", StaticFiles(directory="/static"), name="static")
app.mount("/", StaticFiles(directory="/pages"), name="pages")
# add websocket
app.mount("/ws", asgi, name="socket") After: # Main router for the API.
app.include_router(router=api_router, prefix="/api")
# add websocket
app.mount("/ws", asgi, name="socket")
# add static files
app.mount("/static", StaticFiles(directory="/static"), name="static")
app.mount("/", StaticFiles(directory="/pages"), name="pages") Ref: encode/starlette#1548 and https://www.starlette.io/routing/#route-priority |
This example sets up a FastAPI application that listens for connect and disconnect events using the socket.io library. The socketio_endpoint function attaches the incoming WebSockets to the socket.io server. You can add more event handlers as needed for your application.
|
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
Description
How can I use socket.io instead of the plain websocket integration? I guess this is more a question belonging to starlette.
Currently migrating from a flask application using flask-socketio / python-socketio
Any hint is appreciated. Thx.
The text was updated successfully, but these errors were encountered: