0

I'm kinda new with react and react-admin. The task is pretty simple, it is to connect FastAPI server with react-admin app via websocket. I think I have to create websocket dataProvider somehow.

for react-admin App.tsx


export const App = () => (

    <Admin
        dataProvider={dataProvider}
    >
        <Resource name="" list={} show={} />
    </Admin>
);

dataProvider.tsx

import jsonServerProvider from 'ra-data-json-server';

const URL = 'http://127.0.0.1:8000/'


export const dataProvider = jsonServerProvider(
    URL
);

When I simple change http to ws it gives an error url scheme 'ws' is not supported because it use fetch(), and fetch() work with http\s only.

I think there is no need of my FastAPI code but whatever:

@router.websocket('/ws/send-data/')
async def ws_send_users(websocket: WebSocket):
    print('2 in ws_send_users')
    await websocket.accept()
    while True:
        await websocket.send_text('text1')
        await asyncio.sleep(0.25)


@router.websocket('/ws/send-data/{user_inner}')
async def ws_send_user(websocket: WebSocket,
                       user_inner: str = None):
    print('1 in ws_send_user')

    await websocket.accept()
    while True:
        if not user_inner:
            return await ws_send_users(websocket)
        await websocket.send_text('text2')
        await asyncio.sleep(0.25)

With default http it works just perfect: ws_send_user is called when we want to show user in react-admin, and ws_send_users is called when we want to list users

this code creates websocket connection and gets events just fine but I think there is something wrong with it. Anyway IDK how to connect it with react-admin interface (list and show options).

export const App = () => (

    <Admin
        dataProvider={useEffect(() => {
            const WS = new WebSocket(`ws://127.0.0.1:8000/ws/send-data/`);
            WS.onmessage = e => {
                console.log('el', e.data)
                e.data && !(USERS.includes(e.data)) ? USERS.push(e.data) : null;
            }

        })}
    >
        <Resource name="" list={} show={} />
    </Admin>
);

the purpose is to get list of users to list and each separate user to show by some react-admin magic, so please if you're experienced with it help me.

  • You might find [this answer](https://stackoverflow.com/a/74639030/17865804), as well as [this](https://stackoverflow.com/a/72070914/17865804) and [this](https://stackoverflow.com/a/70996841/17865804) helpful. – Chris Jun 20 '23 at 04:44
  • @Chris thank you, it wan't obvious idea for me, I'll try it soon. – Max Shylnikov Jun 20 '23 at 12:09
  • Unfortunately, this isn't working for `react-admin` library. Please, pay attention that I search a solution not for `FastAPI`, `JavaScript` or `React`. I think I'm missing something. – Max Shylnikov Jun 20 '23 at 12:35
  • "When I simple change http to ws it gives an error `url scheme 'ws' is not supported` because it use fetch(), and fetch() work with http\s only." I need specific `react-admin` websocket connection (to connect dataProvider via websocket) – Max Shylnikov Jun 20 '23 at 16:08

1 Answers1

0

Ok, I think I've connected it. Since I'm newbie with JS and React, I would like to impore the quality of the code

class WebSocketDataProvider {
    constructor() {
        this.apiUrl = `ws://yourhost:yourport/ws/send-data/`;
        this.socket = new WebSocket(this.apiUrl);
        this.socket.addEventListener('open', this.handleSocketOpen);
        this.socket.addEventListener('message', this.handleSocketMessage);
        this.socket.addEventListener('error', this.handleSocketError);
        this.socket.addEventListener('close', this.handleSocketClose);
    }

    handleSocketOpen = () => {
        console.log('WebSocket connection is open');
    };

    handleSocketMessage = (event) => {
        this.getList(event);
    };

    handleSocketError = (event) => {
        console.log('HandleSocketError', event)
    };

    handleSocketClose = (event) => {
        console.log('HandleSocketClose', event)
    };

    getList = (event) => {

        return new Promise((resolve, reject) => {
            const handleResponse = (event) => {
                const parsedResponse = JSON.parse(event.data);
                let response = {
                    data: [],
                    total: Object.keys(parsedResponse).length,
                }
                Object.entries(parsedResponse).forEach((key, value) => {
                    let obj = {
                        id: key[0],
                        urls: key[1],
                    }
                    response.data.push(obj);
                });
                resolve(response);
                this.socket.removeEventListener('message', handleResponse);
            }
            this.socket.addEventListener('message', handleResponse);
        });
    };

    getOne = (event) => {

        return new Promise((resolve, reject) => {
            const handleResponse = (event) => {
                const parsedResponse = JSON.parse(event.data);
                const href = location.href.split('/');
                const length = href.length
                const userId = href[length - 2]
                let response = {
                    data:
                    {
                        id: userId,
                        urls: parsedResponse.userId,
                    }
                }

                resolve(response);
                this.socket.removeEventListener('message', handleResponse);
            }
            this.socket.addEventListener('message', handleResponse);
        });
    };
}

const dataProvider = new WebSocketDataProvider;
export default dataProvider;