Demo using Slices Network GraphQL Relay API to make a teal.fm client
at main 3.3 kB view raw
1import { StrictMode, Suspense } from "react"; 2import { createRoot } from "react-dom/client"; 3import { BrowserRouter, Route, Routes } from "react-router-dom"; 4import "./index.css"; 5import App from "./App.tsx"; 6import Profile from "./Profile.tsx"; 7import TopTracks from "./TopTracks.tsx"; 8import TopAlbums from "./TopAlbums.tsx"; 9import LoadingFallback from "./LoadingFallback.tsx"; 10import { RelayEnvironmentProvider } from "react-relay"; 11import { 12 Environment, 13 type FetchFunction, 14 type GraphQLResponse, 15 Network, 16 Observable, 17 type SubscribeFunction, 18} from "relay-runtime"; 19import { createClient } from "graphql-ws"; 20 21const HTTP_ENDPOINT = 22 "https://quickslice-production-d668.up.railway.app/graphql"; 23 24const WS_ENDPOINT = "wss://quickslice-production-d668.up.railway.app/graphql"; 25 26const fetchGraphQL: FetchFunction = async (request, variables) => { 27 const resp = await fetch(HTTP_ENDPOINT, { 28 method: "POST", 29 headers: { "Content-Type": "application/json" }, 30 body: JSON.stringify({ query: request.text, variables }), 31 }); 32 if (!resp.ok) { 33 throw new Error("Response failed."); 34 } 35 return await resp.json(); 36}; 37 38const wsClient = createClient({ 39 url: WS_ENDPOINT, 40 retryAttempts: 5, 41 shouldRetry: () => true, 42 on: { 43 connected: () => { 44 console.log("WebSocket connected!"); 45 }, 46 error: (error) => { 47 console.error("WebSocket error:", error); 48 }, 49 closed: (event) => { 50 console.log("WebSocket closed:", event); 51 }, 52 }, 53}); 54 55const subscribe: SubscribeFunction = (operation, variables) => { 56 return Observable.create((sink) => { 57 if (!operation.text) { 58 sink.error(new Error("Missing operation text")); 59 return; 60 } 61 62 return wsClient.subscribe( 63 { 64 operationName: operation.name, 65 query: operation.text, 66 variables, 67 }, 68 { 69 next: (data) => { 70 if (data.data !== null && data.data !== undefined) { 71 sink.next({ data: data.data } as GraphQLResponse); 72 } 73 }, 74 error: (error) => { 75 console.error("Subscription error:", error); 76 if (error instanceof Error) { 77 sink.error(error); 78 } else if (error instanceof CloseEvent) { 79 sink.error( 80 new Error(`WebSocket closed: ${error.code} ${error.reason}`), 81 ); 82 } else { 83 sink.error(new Error(JSON.stringify(error))); 84 } 85 }, 86 complete: () => sink.complete(), 87 }, 88 ); 89 }); 90}; 91 92const environment = new Environment({ 93 network: Network.create(fetchGraphQL, subscribe), 94}); 95 96createRoot(document.getElementById("root")!).render( 97 <StrictMode> 98 <BrowserRouter> 99 <RelayEnvironmentProvider environment={environment}> 100 <Suspense fallback={<LoadingFallback />}> 101 <Routes> 102 <Route path="/" element={<App />} /> 103 <Route path="/tracks" element={<TopTracks />} /> 104 <Route path="/tracks/:period" element={<TopTracks />} /> 105 <Route path="/albums" element={<TopAlbums />} /> 106 <Route path="/albums/:period" element={<TopAlbums />} /> 107 <Route path="/profile/:handle" element={<Profile />} /> 108 </Routes> 109 </Suspense> 110 </RelayEnvironmentProvider> 111 </BrowserRouter> 112 </StrictMode>, 113);