-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: realtime API and Payload ORM #11334
base: main
Are you sure you want to change the base?
Conversation
…ve console.logs, etc
would it be feasible to combine this idea with ritsu's fully typed sdk? I think it'd be a pretty nice DX to just be able to pass Just thinking out loud. I haven't looked in to the code itself yet, but I think it'd be genuinely game changing if we could provide initial state via the local api/server, use the rest API for things like infinite scrolling and interaction that must take place on the client and then the icing on the cake, to simply be able to tell the data to always be in realtime would be one of the greatest features of payload overall. |
Definitely! This is precisely why we agreed to review that PR soon. About the name, thanks for the feedback! I agree that we need something better. As far as the vanilla option goes, we could just use the sdk's third argument object to configure this behavior: const [initialPostsCount, onChangePostsCount] = await sdk.count(
{ collection: 'posts' },
{
// option 1: `realtime` prop. If true, we return a tuple of [initialResult, onChange]
// I think the first element of the tuple can be confusing (people might think it's reactive)
realtime: true,
// option 2: onChange callback. if defined, realtime is assumed. No tuple returned
onChange: (result) => { /** ... */ }
},
) As far as the react hook goes, I like the idea of it being reactive/real-time by default and that being opt-out. There is also the option of not having a default and making the I'd love to hear your thoughts on the default value for real-time both in vanilla and react, as well as possible names for the react hook I also thought about infinite scrolling and it deserves further thought... could it be part of the react hook somehow? 🤔 |
PayloadQuery
Currently you can stream DB updates to the client using a polling strategy (refetching at intervals). For example, to get the number of posts with react-query:
This has some problems:
To solve these problems, we are introducing
payloadQuery
.To use it in React, you need to wrap your app with
PayloadQueryClientProvider
:Now you can use the
usePayloadQuery
hook anywhere in your app:This will automatically update the data when the DB changes!
You can use all 3 Local API reading methods:
find
,findById
, andcount
(with all their possible parameters: where clauses, pagination, etc.).How it works
Under the hood,
PayloadQueryClientProvider
opens a single centralized connection that is kept alive, and is used to listen and receive updates via Server Sent Events (SSE). The initial request is made with a normal HTTP request that does not require keep-alive.The same queries are cached on the client and server, so as not to repeat them unnecessarily.
On the server, the
afterChange
andafterDelete
hooks are used to loop through all registered queries and fire them if they have been invalidated. Invalidation logic allows for incremental improvements. Instead of naively invalidating all queries for any change in the database, we can analyze the type of operation, the collection, or options such as the where clause.What if I don't use React?
This plugin was intentionally made framework-agnostic, in vanilla javascript:
The React version is just a small wrapper around these functions. Feel free to bind it to your UI framework of choice!
What if I use Vercel / Serverless?
Serverless platforms like Vercel don't allow indefinitely alive connections (either HTTP or WebSockets).
This API has a reconnection logic that can solve some problems, but even then when the server reconnects the queries stored in memory would be lost, so the client might miss some updates.
We want to explore later how to solve this, either by storing it in the payload database or in some external service or server.
TODO
find
,findById
orcount
). But I would like to make the responses type-safe as well, like in an ORM. My idea is to pass an auto-generated parser to theClientProvider
that follows the collections interface.EDIT: Luckily I didn't start doing this, I wasn't aware that this work was already being done with the SDK. Using that package could simplify the development of this one.
/ui
package.PayloadQuery
because of the similarity to react-query, but it actually does quite a bit more than react-query. There are many related terms that come to mind:RCP
,ORM
,real-time
,reactive
, etc.