0

The Socket.IO app, which is mounted to the FastAPI app on the root route ('/'), is functioning correctly. However, when I attempt to change the route from the root ('/') to '/ws', the Socket.IO functionality is not working as expected.

here is the server.py

from fastapi import FastAPI, Request
import uvicorn
from fastapi import FastAPI, WebSocket
from fastapi.middleware.cors import CORSMiddleware
from typing import Union

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
    expose_headers=["Content-Disposition"],
)


@app.middleware("http")
async def cors_middleware(request: Request, call_next):
    if request.url.path == "/ws":
        # Exclude the /ws route from CORS headers
        response = await call_next(request)
    else:
        # Apply CORS headers for other routes
        response = await call_next(request)
        response.headers["Access-Control-Allow-Origin"] = "*"
        response.headers["Access-Control-Allow-Headers"] = "*"
        response.headers["Access-Control-Allow-Methods"] = "*"
    return response


# @app.get("/ws")
# def read_root():
#     return {"Hello": "World"}


@app.get("/items/{item_id}")
def read_item(item_id: int, q: Union[str, None] = None):
    return {"item_id": item_id, "q": q}


from sockets import sio_app

app.mount('/ws', sio_app)

if __name__ == '__main__':
    uvicorn.run("main:app", reload=True, port=1111)

here is sockets.py

import socketio
from fastapi import Depends, HTTPException, status

sio_server = socketio.AsyncServer(async_mode='asgi',
                                  cors_allowed_origins='*')

sio_app = socketio.ASGIApp(socketio_server=sio_server,
                           # socketio_path="sockets"
                           )

active_connections = []


@sio_server.event
async def connect(sid, environ, auth):
    print(f'connected auth={auth} sid={sid}')
    active_connections.append(sid)
    print(f"Active connections:- {str(active_connections)}")
    await sio_server.emit('chat', {'data': 'Connected', 'sid': sid}, room=sid)


@sio_server.event
def disconnect(sid):
    print('disconnected', sid)
    active_connections.remove(sid)
    print(f"Active connections:- {str(active_connections)}")


@sio_server.on('query')
async def test_message(sid, message):
    print(message)
    await sio_server.emit('chat', {'data': message + " -Interaction Engine"}, room=sid)

# server --> query
#
# client --> chat

here is client.py

import socketio
import asyncio

sio = socketio.AsyncClient()


async def connect():
    try:
        connection_task = asyncio.create_task(sio.connect('http://localhost:1111/ws', auth={"token": "dataa121asdadsassda"}))
        await asyncio.wait_for(connection_task, timeout=30)
        print('Connected to server')
    except asyncio.TimeoutError:
        print('Connection timed out')
    except Exception as e:
        print(f'Error occurred while connecting: {str(e)}')


@sio.on('connect')
async def on_connect():
    print('Connected to server')


@sio.on('chat')
def on_chat(data):
    print('Received message:', data)


@sio.on('disconnect')
def on_disconnect():
    print('Disconnected from server')


async def main():
    await connect()

    await sio.emit('query', 'Hello, server!, from client')

    await asyncio.sleep(1)

    await sio.disconnect()


if __name__ == '__main__':
    asyncio.run(main())

have also tried in POSTMAN ,

when I try it using client.py I am getting bellow error

Connection timed out
Traceback (most recent call last):
  File "/Users/bharatkundapur/Documents/Workspace/Socketio_Poc/client.py", line 44, in <module>
    asyncio.run(main())
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/asyncio/base_events.py", line 646, in run_until_complete
    return future.result()
  File "/Users/bharatkundapur/Documents/Workspace/Socketio_Poc/client.py", line 36, in main
    await sio.emit('query', 'Hello, server!, from client')
  File "/Users/bharatkundapur/Documents/Workspace/Envs/Socketio_Poc/lib/python3.10/site-packages/socketio/asyncio_client.py", line 213, in emit
    raise exceptions.BadNamespaceError(
socketio.exceptions.BadNamespaceError: / is not a connected namespace.

when I try using postman I see bellow logs in the server

connection failed (403 Forbidden) Postman and same in the postman.

1 Answers1

0

The issue has been resolved, and I forgot to share the solution. Here's the answer to the question above.

In the file sockets.py, the socketio_path is not defined, and its default value is socket.io.

When we want to attach the sio_app to the fast API app route '/ws,' we can achieve this by using the following line of code in the server.py:

app.mount('/ws', sio_app)

assuming the app is hosted in the local environment.

However, when attempting to connect and establish a duplex connection through the web socket endpoint, using http://localhost:8888/ws is incorrect. Just because we have mounted the sio_app at the '/ws' route does not mean the sio_app is available at http://localhost:8888/ws.

The solution is to access the http://localhost:8888/ endpoint with socketio_path='/ws/socket.io'.