variable-lime
variable-lime•5mo ago

Live provider example

I am using django strawberry backend with graphql. I want to start a live provider from refine. Can you show me a simple example how to define and use a live provider with these components?
63 Replies
kapa.ai
kapa.ai•5mo ago
Hi @Valugar. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- I'm sorry, but the knowledge sources provided do not contain specific examples of using a live provider with a Django Strawberry backend and GraphQL in Refine. However, I can guide you on how to generally set up a live provider in Refine using GraphQL. Firstly, you need to create a live provider. Here is a general example of how you can do 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>
);
};
(Source: Refine Documentation (https://refine.dev/docs/guides-concepts/realtime#usage-1)) In this example, liveProvider is imported from a local file and used in the Refine component. The createClient function from graphql-ws is used to create a GraphQL WebSocket client, which is then passed to the liveProvider. Please note that you need to replace "YOUR_WS_URL" with your actual WebSocket URL. Refine remains agnostic in its API to allow different solutions to be integrated. Therefore, you should be able to adapt this example to work with Django Strawberry and GraphQL. For more detailed information, you can refer to the Refine Live Provider documentation (https://refine.dev/docs/realtime/live-provider/). Remember to install the necessary packages for your project. For example, if you're using Ably for Realtime features, you would need to install the Ably live provider package from Refine:
npm i @refinedev/ably
npm i @refinedev/ably
(Source: Refine Documentation (https://refine.dev/docs/advanced-tutorials/real-time)) I hope this helps! If you have more specific questions or run into any issues, feel free to ask. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai•5mo ago
<@240371095444652032> kapa.ai is still learning and improving, please let us know how it did by reacting below
variable-lime
variable-lime•5mo ago
@kapa.ai I keep getting error: Argument 'input' of required type 'CreateLocationSubscriptionFilterInput!' was provided the variable '$input' which was not provided a runtime value. For this: @strawberry.input class CreateLocationSubscriptionFilterInput: gateway_id: Optional[str] timestamp: Optional[datetime] latitude: Optional[float]
longitude: Optional[float] @strawberry.input class UpdateLocationSubscriptionFilterInput: gateway: Optional[str] timestamp: Optional[datetime] latitude: Optional[float] longitude: Optional[float] @strawberry.input class DeleteLocationSubscriptionFilterInput: gateway: Optional[str] timestamp: Optional[datetime]
@strawberry.type class Subscription: @strawberry.subscription async def created_location(self, input: CreateLocationSubscriptionFilterInput) -> AsyncGenerator[LocationType, None]: while True: await asyncio.sleep(0.5)
new_locations = await sync_to_async(Location.objects.filter, thread_sensitive=True)( **{k: v for k, v in vars(input).items() if v is not None} ) for location in new_locations: yield LocationType.from_django(location) And I am doing a simple live provider refine with: const { data: locations, isLoading: locationIsLoading } = useList({ resource: "locations", meta: { gqlQuery: LOCATIONS_LIST_QUERY }, pagination: { pageSize: 999 }, liveMode: "auto", }); and export const LOCATIONS_LIST_QUERY = gql query LocationsList( $filter: LocationFilter! $sorting: [LocationSort!] $paging: OffsetPaging! ) { locations(filter: $filter, sorting: $sorting, paging: $paging) { nodes { gateway { id serialNumber vehicle{ id make model events{ description createdAt } drivers{ id name } } } location timestamp } totalCount } } ;
kapa.ai
kapa.ai•5mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- The error message you're seeing suggests that the input variable for your created_location subscription is not being provided a value at runtime. This means that when your subscription is being called, it's not receiving the necessary input argument. In your Refine useList hook, you're using liveMode: "auto", which means Refine will automatically subscribe to the created, updated, and deleted events for the locations resource. However, it seems like your backend expects an input argument for the created_location subscription, which is not being provided. To resolve this issue, you need to ensure that the input argument is provided when the created_location subscription is called. This could be done in your GraphQL query or in your Refine code where you're setting up the subscription. Unfortunately, the provided knowledge sources do not contain specific examples or code snippets that show how to provide an input argument for a subscription in Refine. For more detailed information, you can refer to the Refine Live Provider documentation (https://refine.dev/docs/realtime/live-provider/). If you're still having trouble, I would recommend reaching out to the Refine community or checking the Strawberry GraphQL documentation for more specific guidance on handling subscriptions with input arguments. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai•5mo ago
<@240371095444652032> kapa.ai is still learning and improving, please let us know how it did by reacting below
variable-lime
variable-lime•5mo ago
@kapa.ai I keep getting Argument 'input' of required type 'CreateLocationSubscriptionFilterInput!' was provided the variable '$input' which was not provided a runtime value. no matter how I modify my backend. @strawberry.input class CreateLocationSubscriptionFilterInput: filter: LocationFilter
@strawberry.input class UpdateLocationSubscriptionFilterInput: gateway: Optional[str] timestamp: Optional[datetime] latitude: Optional[float] longitude: Optional[float] @strawberry.input class DeleteLocationSubscriptionFilterInput: gateway: Optional[str] timestamp: Optional[datetime]
@strawberry.type class Subscription: @strawberry.subscription async def created_location(self, input: CreateLocationSubscriptionFilterInput) -> AsyncGenerator[LocationType, None]: while True: await asyncio.sleep(0.5)
new_locations = await sync_to_async(Location.objects.filter, thread_sensitive=True)( **{k: v for k, v in vars(input).items() if v is not None} ) for location in new_locations: yield LocationType.from_django(location)
kapa.ai
kapa.ai•5mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- The error message you're seeing suggests that the input variable for your created_location subscription is not being provided a value at runtime. This means that when your subscription is being called, it's not receiving the necessary input argument. In your Refine useList hook, you're using liveMode: "auto", which means Refine will automatically subscribe to the created, updated, and deleted events for the locations resource. However, it seems like your backend expects an input argument for the created_location subscription, which is not being provided. To resolve this issue, you need to ensure that the input argument is provided when the created_location subscription is called. This could be done in your GraphQL query or in your Refine code where you're setting up the subscription. Unfortunately, the provided knowledge sources do not contain specific examples or code snippets that show how to provide an input argument for a subscription in Refine. For more detailed information, you can refer to the Refine Live Provider documentation (https://refine.dev/docs/realtime/live-provider/). If you're still having trouble, I would recommend reaching out to the Refine community or checking the Strawberry GraphQL documentation for more specific guidance on handling subscriptions with input arguments. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai•5mo ago
<@240371095444652032> kapa.ai is still learning and improving, please let us know how it did by reacting below
variable-lime
variable-lime•5mo ago
@kapa.ai Ok, so if I change the created_location to: @strawberry.type class Subscription: @strawberry.subscription async def created_location(self) -> AsyncGenerator[LocationType, None]: while True: await asyncio.sleep(0.5)
new_locations = await sync_to_async(Location.objects.filter, thread_sensitive=True)( **{k: v for k, v in vars(input).items() if v is not None} ) for location in new_locations: yield LocationType.from_django(location) will this work?
kapa.ai
kapa.ai•5mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- In the code you provided, you removed the input argument from the created_location subscription, but you're still trying to use input in the body of the function. This will result in an error because input is not defined. If you want to remove the input argument, you should also remove or modify the line where you're using input:
new_locations = await sync_to_async(Location.objects.filter, thread_sensitive=True)(
**{k: v for k, v in vars(input).items() if v is not None}
)
new_locations = await sync_to_async(Location.objects.filter, thread_sensitive=True)(
**{k: v for k, v in vars(input).items() if v is not None}
)
You need to replace this with a logic that doesn't rely on input. However, without knowing more about your application and what you're trying to achieve, it's hard to suggest a specific solution. If you want to fetch all new locations without any filter, you could potentially simplify this to:
new_locations = await sync_to_async(Location.objects.all, thread_sensitive=True)()
new_locations = await sync_to_async(Location.objects.all, thread_sensitive=True)()
This will fetch all locations from your database every 0.5 seconds. Please note that this could be inefficient if you have a large number of locations. Remember to always test your changes to ensure they work as expected. If you're still having trouble, I would recommend reaching out to the Refine community or checking the Strawberry GraphQL documentation for more specific guidance. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
variable-lime
variable-lime•5mo ago
@kapa.ai I am still very much confused. I have this in the frontend: const { data: locations, isLoading: locationIsLoading } = useList({ resource: "locations", meta: { gqlQuery: LOCATIONS_LIST_QUERY }, pagination: { pageSize: 999 }, liveMode: "auto", }); with export const LOCATIONS_LISTQUERY = gql query LocationsList( $filter: LocationFilter! $sorting: [LocationSort!] $paging: OffsetPaging! ) { locations(filter: $filter, sorting: $sorting, paging: $paging) { nodes { gateway { id serialNumber vehicle{ id make model events{ description createdAt } drivers{ id name } } } location timestamp } totalCount } } ; And over on the backend I set it as: @strawberry.input class LocationFilter: id: Optional[StringFilter] = None gateway: Optional[StringFilter] = None location: Optional[StringFilter] = None timestamp: Optional[DateTimeFilter] = None and: Optional[List['LocationFilter']] = strawberry.field(name="and", defaultfactory=list) or: Optional[List['LocationFilter']] = strawberry.field(name="or", default_factory=list) @strawberry.input class CreateLocationSubscriptionFilterInput: filter: LocationFilter @strawberry.type class Subscription: @strawberry.subscription async def created_location(self) -> AsyncGenerator[LocationType, None]: while True: await asyncio.sleep(0.5)
new_locations = await sync_to_async(Location.objects.all, thread_sensitive=True)() for location in new_locations: yield LocationType.from_django(location) And I keep getting the error: "Variable '$input' expected value of type 'CreateLocationSubscriptionFilterInput' which cannot be used as an input type."
kapa.ai
kapa.ai•5mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- The error message you're seeing suggests that the CreateLocationSubscriptionFilterInput type is not recognized as a valid input type in your GraphQL schema. This could be due to a few reasons: 1. The CreateLocationSubscriptionFilterInput type is not correctly defined or not included in your GraphQL schema. Make sure that the CreateLocationSubscriptionFilterInput type is correctly defined in your Strawberry schema and that it's included in the schema that your GraphQL server is using. 2. The CreateLocationSubscriptionFilterInput type is not used as an input type in any of your GraphQL operations. In your created_location subscription, you're not using the CreateLocationSubscriptionFilterInput type as an input. If you're not using this type as an input in any of your GraphQL operations, GraphQL might not recognize it as a valid input type. 3. There's a mismatch between the CreateLocationSubscriptionFilterInput type in your frontend and backend code. Make sure that the CreateLocationSubscriptionFilterInput type in your frontend code matches the CreateLocationSubscriptionFilterInput type in your backend code. Unfortunately, the provided knowledge sources do not contain specific examples or code snippets that show how to define and use the CreateLocationSubscriptionFilterInput type in Refine. For more detailed information, you can refer to the Refine Live Provider documentation (https://refine.dev/docs/realtime/live-provider/). If you're still having trouble, I would recommend reaching out to the Refine community or checking the Strawberry GraphQL documentation for more specific guidance on defining and using input types. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
variable-lime
variable-lime•5mo ago
@kapa.ai Ah I see. Now help me then implement the create/update/ and deletion subscription please. import strawberry from ..types import LocationType from ..models import Location from .schem_types import CreateLocationSubscriptionFilterInput, UpdateOneLocationSubscriptionFilterInput, DeleteOneLocationSubscriptionFilterInput from strawberry.types import Info from typing import AsyncGenerator from typing import Optional from asgiref.sync import sync_to_async import asyncio @strawberry.type class Subscription: @strawberry.subscription async def created_location(self, input: Optional[CreateLocationSubscriptionFilterInput] = None) -> AsyncGenerator[LocationType, None]: while True: await asyncio.sleep(0.5)
query = Location.objects.all() if input: query = query.filter({k: v for k, v in vars(input).items() if v is not None}) print(query) location_event = await location_events.get() yield location_event @strawberry.subscription async def updated_one_location(self, input: Optional[UpdateOneLocationSubscriptionFilterInput] = None) -> AsyncGenerator[LocationType, None]: while True: await asyncio.sleep(0.5)
query = Location.objects.all() print("updated_one_location", query) if input: query = query.filter(
{k: v for k, v in vars(input).items() if v is not None}) print(query) new_locations = await sync_to_async(list)(query) for location in new_locations: print(location) yield LocationType( location = location ) @strawberry.subscription async def deleted_one_location(self, input: Optional[DeleteOneLocationSubscriptionFilterInput] = None) -> AsyncGenerator[LocationType, None]: while True: await asyncio.sleep(0.5)
query = Location.objects.all() print("updated_one_location", query) if input: query = query.filter(**{k: v for k, v in vars(input).items() if v is not None}) print(query) new_locations = await sync_to_async(list)(query) for location in new_locations: print(location) yield LocationType( location = location ) pass
kapa.ai
kapa.ai•5mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- Your backend code for the created_location, updated_one_location, and deleted_one_location subscriptions seems to be correctly set up. Each subscription is an asynchronous generator that yields new LocationType instances. The input argument is optional and is used to filter the locations that are returned. On the frontend, you can use Refine's useSubscription hook to subscribe to these events. Here's a general example of how you can do this:
import { useSubscription } from "@refinedev/core";

const { data } = useSubscription({
resource: "locations",
event: "created",
variables: { input: { /* your input values */ } },
});
import { useSubscription } from "@refinedev/core";

const { data } = useSubscription({
resource: "locations",
event: "created",
variables: { input: { /* your input values */ } },
});
In this example, useSubscription is used to subscribe to the created event for the locations resource. The variables prop is used to provide the input argument for your subscription. You should replace /* your input values */ with the actual values you want to use for the input argument. You can do the same for the updated and deleted events:
const { data: updatedData } = useSubscription({
resource: "locations",
event: "updated",
variables: { input: { /* your input values */ } },
});

const { data: deletedData } = useSubscription({
resource: "locations",
event: "deleted",
variables: { input: { /* your input values */ } },
});
const { data: updatedData } = useSubscription({
resource: "locations",
event: "updated",
variables: { input: { /* your input values */ } },
});

const { data: deletedData } = useSubscription({
resource: "locations",
event: "deleted",
variables: { input: { /* your input values */ } },
});
Please note that you need to replace /* your input values */ with the actual values you want to use for the input argument. Unfortunately, the provided knowledge sources do not contain specific examples or code snippets that show how to use the useSubscription hook in Refine. For more detailed information, you can refer to the Refine Live Provider documentation (https://refine.dev/docs/realtime/live-provider/). I hope this helps! If you have more specific questions or run into any issues, feel free to ask. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai•5mo ago
<@240371095444652032> kapa.ai is still learning and improving, please let us know how it did by reacting below