ambitious-aqua
ambitious-aqua3mo ago

How the subscription works when enabling Live provider for graphql?

Hi all, I would like to understand how Refine triggers subscriptions for instance in the CRM example. Below are my concerns: 1. I don't see how, based on API schemas, Refine prepare and run subscriptions for the different events. 2. Also, how Refine "plugs" a subscription response and a resource related in order to feed the appropriate screen with received data I thank in advance anyone keen to help me, as I am a real newbie in Refine. Regards
37 Replies
kapa.ai
kapa.ai3mo ago
Hi @Poutieu. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Hello, Refine uses the concept of a Live Provider to handle real-time updates in your application. The Live Provider is an object that contains subscribe, unsubscribe, and publish methods. These methods are used by Refine to subscribe to updates for a certain resource, unsubscribe from these updates, and publish updates respectively. You can see an example of a basic Live Provider in the Refine documentation (https://refine.dev/docs/guides-concepts/realtime#live-provider). When you call the useList, useOne, or useMany hooks in your application, they will call the subscribe method of the Live Provider. This allows you to create subscription queries using the parameters of these hooks. After creating the subscription query, Refine will listen to it using the graphql-ws client and return the unsubscribe method to use in the unsubscribe method of the Live Provider. You can see an example of this in the Refine documentation (https://refine.dev/docs/guides-concepts/realtime#implementing-subscribe-method-1). In the case of GraphQL, the only difference between queries and subscriptions is the subscription keyword. This means that you can use the same logic for both queries and subscriptions. Refine already has a data provider for creating GraphQL queries, so it uses the same logic for GraphQL subscriptions. You can see an example of this in the Refine documentation (https://refine.dev/docs/guides-concepts/realtime#creating-a-live-provider-with-graphql-subscriptions). Once you have created your Live Provider, you can use it in your application like this:
import { Refine } from "@refinedev/core";
import { createClient } from "graphql-ws";

import { liveProvider } from "./liveProvider";

const gqlWebSocketClient = createClient({
url: "YOUR_WS_URL",
});

const App: React.FC = () => {
return <Refine liveProvider={liveProvider(gqlWebSocketClient)}>{/* ... */} </Refine>;
};
import { Refine } from "@refinedev/core";
import { createClient } from "graphql-ws";

import { liveProvider } from "./liveProvider";

const gqlWebSocketClient = createClient({
url: "YOUR_WS_URL",
});

const App: React.FC = () => {
return <Refine liveProvider={liveProvider(gqlWebSocketClient)}>{/* ... */} </Refine>;
};
You can see an example of this in the Refine documentation (https://refine.dev/docs/guides-concepts/realtime#usage-1). As for your second question, Refine hooks will create a subscription query using the parameters of the useSubscription hook and listen to it. When a live event is received, it will call the onLiveEvent method of the useSubscription hook. You can see an example of this in the Refine documentation (https://refine.dev/docs/guides-concepts/realtime#implementing-subscribe-method-1). I hope this helps! Let me know if you have any other questions. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3mo ago
<@1190340771946188961> kapa.ai is still learning and improving, please let us know how it did by reacting below
ambitious-aqua
ambitious-aqua3mo ago
@kapa.ai does it mean I have to write in my backend a subscription operation for each query operation?
kapa.ai
kapa.ai3mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- Yes, in order to use GraphQL subscriptions, you would need to define a subscription operation for each query operation in your backend that you want to receive real-time updates for. GraphQL subscriptions are a way to push data from the server to the clients that choose to listen to real-time updates from the server. Subscriptions are similar to queries in that they specify a set of fields to be delivered to the client, but instead of immediately returning a single answer, a result is sent every time a particular event happens on the server. So, if you have a query operation that fetches data from a certain resource and you want to get real-time updates for that resource, you would need to define a subscription operation for it in your backend. You can find more information about GraphQL subscriptions in the GraphQL documentation (https://graphql.org/blog/subscriptions-in-graphql-and-relay/). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3mo ago
<@1190340771946188961> kapa.ai is still learning and improving, please let us know how it did by reacting below
ambitious-aqua
ambitious-aqua3mo ago
Thanks @kapa.ai Do Refine needs to be told programmatically to connect and listen to events?
kapa.ai
kapa.ai3mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- Yes, Refine needs to be configured to connect and listen to events for real-time updates. This is done by setting up a Live Provider and passing it to the Refine component. A Live Provider is an object that contains subscribe, unsubscribe, and publish methods. These methods are used by Refine to subscribe to updates for a certain resource, unsubscribe from these updates, and publish updates respectively. Here's an example of how you can set up a Live Provider and pass it to the Refine component:
import { Refine } from "@pankod/refine";
import { createClient } from "graphql-ws";

import { liveProvider } from "./liveProvider";

const gqlWebSocketClient = createClient({
url: "YOUR_WS_URL",
});

const App: React.FC = () => {
return (
<Refine liveProvider={liveProvider(gqlWebSocketClient)}>
{/* ... */}
</Refine>
);
};
import { Refine } from "@pankod/refine";
import { createClient } from "graphql-ws";

import { liveProvider } from "./liveProvider";

const gqlWebSocketClient = createClient({
url: "YOUR_WS_URL",
});

const App: React.FC = () => {
return (
<Refine liveProvider={liveProvider(gqlWebSocketClient)}>
{/* ... */}
</Refine>
);
};
In this example, liveProvider is a function that returns a Live Provider object. gqlWebSocketClient is a GraphQL WebSocket client that is used to connect to the server and listen to events. You can find more information about how to set up a Live Provider in the Refine documentation (https://refine.dev/docs/realtime/live-provider/#Refine). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3mo ago
<@1190340771946188961> kapa.ai is still learning and improving, please let us know how it did by reacting below
ambitious-aqua
ambitious-aqua3mo ago
@kapa.ai I rephrase my previous question: let's say I have a certain number of subscription operations in backend, does Refine open a connection to all of them at once or does it depends on the screen I am currently seeing?
kapa.ai
kapa.ai3mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- Refine opens a connection based on the screen you are currently viewing. More specifically, it opens a connection when you call the useList, useOne, or useMany hooks in your application. These hooks will call the subscribe method of the Live Provider, which creates a subscription query using the parameters of these hooks and listens to it. For example, if you're on a screen that uses the useList hook to display a list of resources, Refine will open a connection to subscribe to updates for that specific resource. If you navigate to a different screen that uses the useOne hook to display a single resource, Refine will open a connection to subscribe to updates for that specific resource. This means that Refine doesn't open a connection to all subscription operations at once. Instead, it opens a connection based on the resource you're currently interacting with in your application. You can find more information about this in the Refine documentation (https://refine.dev/docs/guides-concepts/realtime#implementing-subscribe-method-1). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3mo ago
<@1190340771946188961> kapa.ai is still learning and improving, please let us know how it did by reacting below
ambitious-aqua
ambitious-aqua3mo ago
@kapa.ai Perfect!
kapa.ai
kapa.ai3mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- I'm glad you found the information helpful! If you have any more questions about Refine or need further clarification, feel free to ask. Happy coding! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3mo ago
<@1190340771946188961> kapa.ai is still learning and improving, please let us know how it did by reacting below
ambitious-aqua
ambitious-aqua3mo ago
@kapa.ai I would like to know which graphql dependencies I should use to connect to a java graphql API
kapa.ai
kapa.ai3mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- To connect to a GraphQL API with Refine, you would need to use the @refinedev/graphql package. This package provides a data provider for GraphQL APIs that has all the features of Refine without giving up the GraphQL features. You can install it using npm, pnpm, or yarn:
npm i @refinedev/graphql
npm i @refinedev/graphql
pnpm add @refinedev/graphql
pnpm add @refinedev/graphql
yarn add @refinedev/graphql
yarn add @refinedev/graphql
Once installed, you can create a GraphQL client with your API URL and pass it to the dataProvider function to create a data provider:
import Refine from "@refinedev/core";
import dataProvider, { GraphQLClient } from "@refinedev/graphql";

const client = new GraphQLClient("<https://api.example.com/graphql">);

const App = () => (
<Refine
dataProvider={dataProvider(client)}
>
{/* ... */}
</Refine>
);
import Refine from "@refinedev/core";
import dataProvider, { GraphQLClient } from "@refinedev/graphql";

const client = new GraphQLClient("<https://api.example.com/graphql">);

const App = () => (
<Refine
dataProvider={dataProvider(client)}
>
{/* ... */}
</Refine>
);
For real-time features, @refinedev/graphql also provides a liveProvider which uses graphql-ws (https://the-guild.dev/graphql/ws) to handle the connections:
import Refine from "@refinedev/core";
import dataProvider, { GraphQLClient, liveProvider, graphqlWS } from "@refinedev/graphql";

const client = new GraphQLClient("<https://api.example.com/graphql">);
const wsClient = graphqlWS.createClient({ url: "wss://api.example.com/graphql" });

const App = () => (
<Refine
dataProvider={dataProvider(client)}
liveProvider={liveProvider(wsClient)}
options={{ liveMode: "auto" }}
>
{/* ... */}
</Refine>
);
import Refine from "@refinedev/core";
import dataProvider, { GraphQLClient, liveProvider, graphqlWS } from "@refinedev/graphql";

const client = new GraphQLClient("<https://api.example.com/graphql">);
const wsClient = graphqlWS.createClient({ url: "wss://api.example.com/graphql" });

const App = () => (
<Refine
dataProvider={dataProvider(client)}
liveProvider={liveProvider(wsClient)}
options={{ liveMode: "auto" }}
>
{/* ... */}
</Refine>
);
Please note that the language or technology used to implement the GraphQL API (in your case, Java) does not affect the way you connect to it from Refine. As long as the API follows the GraphQL specification, you should be able to connect to it using the @refinedev/graphql package. You can find more information in the Refine documentation (https://refine.dev/docs/data/packages/graphql#usage). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3mo ago
<@1190340771946188961> kapa.ai is still learning and improving, please let us know how it did by reacting below
ambitious-aqua
ambitious-aqua3mo ago
@kapa.ai Good! A last question: how does Refine knows the name of subscription operations hosted by the backend?
kapa.ai
kapa.ai3mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- Refine doesn't automatically know the names of the subscription operations hosted by the backend. Instead, you need to define these operations in your GraphQL schema on the backend, and then use the corresponding names when you set up your subscriptions in Refine. When you call the useSubscription hook in Refine, you pass in a params object that includes a resource property. This resource property should match the name of the subscription operation in your GraphQL schema. Here's an example:
useSubscription({
channel: "posts",
enabled: true,
onLiveEvent: (event) => {
// called when a live event is received
console.log(event);
},
params: {
resource: "posts",
pagination: {
current: 1,
pageSize: 10,
},
subscriptionType: "useList",
},
meta: {
fields: [
"id",
"title",
{
category: ["title"],
},
"content",
"category_id",
"created_at",
],
},
});
useSubscription({
channel: "posts",
enabled: true,
onLiveEvent: (event) => {
// called when a live event is received
console.log(event);
},
params: {
resource: "posts",
pagination: {
current: 1,
pageSize: 10,
},
subscriptionType: "useList",
},
meta: {
fields: [
"id",
"title",
{
category: ["title"],
},
"content",
"category_id",
"created_at",
],
},
});
In this example, "posts" is the name of the subscription operation in the GraphQL schema. When this hook is called, Refine will create a subscription query using this name and the other parameters, and then listen to it. You can find more information about this in the Refine documentation (https://refine.dev/docs/realtime/hooks/use-subscription/). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3mo ago
<@1190340771946188961> kapa.ai is still learning and improving, please let us know how it did by reacting below
ambitious-aqua
ambitious-aqua3mo ago
@kapa.ai so summarise in bullet points, what is the sequence of API calls made ?
kapa.ai
kapa.ai3mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- Sure, here's a summary of the sequence of API calls made by Refine when using GraphQL subscriptions: 1. When a component that uses the useList, useOne, or useMany hooks is rendered, Refine calls the subscribe method of the Live Provider. 2. The subscribe method creates a subscription query using the parameters of the hook and starts listening to it. This involves making a subscription operation to the GraphQL API. 3. When a live event is received, the onLiveEvent method of the hook is called. This method is responsible for handling the received data and updating the component state. 4. When the component is unmounted, or when the parameters of the hook change, Refine calls the unsubscribe method of the Live Provider. This method stops listening to the subscription query. Here's a code example of how you might use the useSubscription hook in Refine:
useSubscription({
channel: "posts",
enabled: true,
onLiveEvent: (event) => {
// handle the received data
console.log(event);
},
params: {
resource: "posts",
pagination: {
current: 1,
pageSize: 10,
},
subscriptionType: "useList",
},
meta: {
fields: [
"id",
"title",
{
category: ["title"],
},
"content",
"category_id",
"created_at",
],
},
});
useSubscription({
channel: "posts",
enabled: true,
onLiveEvent: (event) => {
// handle the received data
console.log(event);
},
params: {
resource: "posts",
pagination: {
current: 1,
pageSize: 10,
},
subscriptionType: "useList",
},
meta: {
fields: [
"id",
"title",
{
category: ["title"],
},
"content",
"category_id",
"created_at",
],
},
});
In this example, "posts" is the name of the subscription operation in the GraphQL schema. When this hook is called, Refine will create a subscription query using this name and the other parameters, and then listen to it. When a live event is received, the console.log(event); line will be executed. You can find more information about this in the Refine documentation (https://refine.dev/docs/realtime/hooks/use-subscription/). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3mo ago
<@1190340771946188961> kapa.ai is still learning and improving, please let us know how it did by reacting below
ambitious-aqua
ambitious-aqua3mo ago
@kapa.ai Is it the same way of functioning that interaction with REST API?
kapa.ai
kapa.ai3mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- No, the interaction with a REST API is different from the interaction with a GraphQL API, especially when it comes to real-time updates. REST APIs are based on HTTP methods like GET, POST, PUT, DELETE, etc. Each of these methods corresponds to a specific operation on a resource. REST APIs are stateless, meaning each request is independent and contains all the information needed to complete the request. On the other hand, GraphQL APIs use a single endpoint that accepts POST requests. The operation to be performed (query, mutation, or subscription) and the data to be fetched or manipulated are defined in the body of the POST request. When it comes to real-time updates, REST APIs typically don't support them out of the box. You would need to implement a mechanism like long polling, server-sent events, or websockets to push updates from the server to the client. GraphQL, however, has built-in support for real-time updates through subscriptions. When you define a subscription operation in your GraphQL schema, the server can push updates to the client whenever the data changes. In Refine, you can enable real-time updates by setting up a Live Provider. For GraphQL APIs, you can use the @refinedev/graphql package, which provides a liveProvider that uses graphql-ws to handle the connections. Here's an example:
import Refine from "@refinedev/core";
import dataProvider, { GraphQLClient, liveProvider, graphqlWS } from "@refinedev/graphql";

const client = new GraphQLClient("<https://api.example.com/graphql">);
const wsClient = graphqlWS.createClient({ url: "wss://api.example.com/graphql" });

const App = () => (
<Refine
dataProvider={dataProvider(client)}
liveProvider={liveProvider(wsClient)}
options={{ liveMode: "auto" }}
>
{/* ... */}
</Refine>
);
import Refine from "@refinedev/core";
import dataProvider, { GraphQLClient, liveProvider, graphqlWS } from "@refinedev/graphql";

const client = new GraphQLClient("<https://api.example.com/graphql">);
const wsClient = graphqlWS.createClient({ url: "wss://api.example.com/graphql" });

const App = () => (
<Refine
dataProvider={dataProvider(client)}
liveProvider={liveProvider(wsClient)}
options={{ liveMode: "auto" }}
>
{/* ... */}
</Refine>
);
You can find more information about this in the Refine documentation (https://refine.dev/docs/data/packages/graphql#usage). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3mo ago
<@1190340771946188961> kapa.ai is still learning and improving, please let us know how it did by reacting below
ambitious-aqua
ambitious-aqua3mo ago
@kapa.ai
kapa.ai
kapa.ai3mo ago
Let me check the knowledge base for you. One moment! :books: Sorry @Poutieu, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist: Perhaps try again in 15mins?
ambitious-aqua
ambitious-aqua3mo ago
@kapa.ai What should I care of in case a REST API with SSE for realtime?
kapa.ai
kapa.ai3mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- When using a REST API with Server-Sent Events (SSE) for real-time updates in Refine, you would need to set up a Live Provider that can handle SSE. Here are some key points to consider: 1. Server-Sent Events (SSE): SSE is a standard that allows a web server to push updates to the client whenever new data is available. It's a good choice for unidirectional data transfer from server to client. However, it's important to note that not all browsers support SSE in service workers, for example, Firefox doesn't support it (source (https://refine.dev/blog/react-websocket-tutorial-nodejs#why-websocket)). 2. Live Provider Setup: You need to set up a Live Provider in Refine to handle real-time updates. The Live Provider is an object that contains subscribe, unsubscribe, and publish methods. These methods are used by Refine to subscribe to updates for a certain resource, unsubscribe from these updates, and publish updates respectively (source (https://refine.dev/docs/realtime/live-provider#publishing-events-from-the-client-side)). 3. Event Publishing: Events published from the server must be in a specific format. For example, when creating, deleting, or updating a record, the event should look like this:
{
channel: `resources/${resource}`,
type: "created", // or "deleted", "updated"
payload: {
ids: [id]
},
date: new Date(),
}
{
channel: `resources/${resource}`,
type: "created", // or "deleted", "updated"
payload: {
ids: [id]
},
date: new Date(),
}
(source (https://refine.dev/docs/realtime/live-provider#publishing-events-from-the-client-side)) 4. Subscription: You can subscribe to specific ids with params. For example, you can subscribe to deleted and updated events from posts resource with id 1 and 2:
useSubscription({
channel: "resources/posts",
type: ["deleted", "updated"],
params: {
ids: ["1", "2"],
},
onLiveEvent: () => setSubscriptionCount((prev) => prev + 1),
});
useSubscription({
channel: "resources/posts",
type: ["deleted", "updated"],
params: {
ids: ["1", "2"],
},
onLiveEvent: () => setSubscriptionCount((prev) => prev + 1),
});
(source (https://refine.dev/docs/advanced-tutorials/real-time#custom-subscriptions)) Please note that the implementation of the Live Provider and the handling of SSE would depend on the specifics of your REST API and your application requirements. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3mo ago
<@1190340771946188961> kapa.ai is still learning and improving, please let us know how it did by reacting below
ambitious-aqua
ambitious-aqua3mo ago
@kapa.ai Do you have a GitHub link for an example that I can check?
kapa.ai
kapa.ai3mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- I'm sorry, but the provided extracts do not contain a specific GitHub link for an example of using a REST API with Server-Sent Events (SSE) for real-time updates in Refine. However, you can refer to the Refine documentation (https://refine.dev/docs/realtime/live-provider) for more information on how to set up a Live Provider for handling real-time updates. For a more specific example, you might want to check out the Refine GitHub repository (https://github.com/pankod/refine) or the Refine examples directory (https://github.com/pankod/refine/tree/master/examples) to see if there's an example that matches your requirements. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3mo ago
<@1190340771946188961> kapa.ai is still learning and improving, please let us know how it did by reacting below
ambitious-aqua
ambitious-aqua3mo ago
@kapa.ai Thank you very much
kapa.ai
kapa.ai3mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- You're welcome! If you have any more questions in the future, don't hesitate to ask. Happy coding! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3mo ago
<@1190340771946188961> kapa.ai is still learning and improving, please let us know how it did by reacting below