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.
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;