-
Notifications
You must be signed in to change notification settings - Fork 36
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
Explore options for reducing the payload sent for live queries #7
Comments
The problem with fast-json-patch it is not easy to create "efficient" patches for lists. E.g. instead of a "remove one item from array" instruction you will get a patch instructions for updating all elements from the array. Maybe it is possible to create better patches using fast-json-patch by denormalizing the GraphQL result tree first. e.g. {
"node": {
"__typename": "Foo",
"id": "18d821",
"items": [
{
"__typename": "Bar",
"id": "12129fc",
"name": "hello"
},
{
"__typename": "Bar",
"id": "12ksasfc",
"name": "foob"
}
]
}
} -> {
"__objects": {
"18d821": {
"__typename": "Foo",
"items": ["$$ref:12129fc", "$$ref:12ksasfc"]
},
"12129fc": {
"__typename": "Bar",
"name": "hello"
},
"12ksasfc": {
"__typename": "Bar",
"name": "foob"
}
},
"__tree": {
"node": "$$ref:18d821"
}
} which should result in smaller patches and also less patch complexity. Let's say the order of array elements changes. That would result in the following patch or the first response: [
{
"op": "replace",
"path": "/node/items/1/name",
"value": "hello"
},
{
"op": "replace",
"path": "/node/items/1/id",
"value": "12129fc"
},
{
"op": "replace",
"path": "/node/items/0/name",
"value": "foob"
},
{
"op": "replace",
"path": "/node/items/0/id",
"value": "12ksasfc"
}
] For the second object that would be: [
{
"op": "replace",
"path": "/__objects/18d821/items/1",
"value": "$$ref:12129fc"
},
{
"op": "replace",
"path": "/__objects/18d821/items/0",
"value": "$$ref:12ksasfc"
}
] |
See #40 |
Is your approach in #40 inventing a new wire-format to avoid shortcomings in existing json patch libraries? Or is a normal standards-compliant JSON patch for a normal standards-compliant GQL result sent over the wire? Which seems far more portable to me. Would it be possible to use your approach to help generate a better - but compliant - JSON patch? Such that a client need not know about anything but json patch? Or is JSON patch as a standard just completely in-appropriate? |
Hey @willstott101, thanks for showing interest 😊 Currently, it is meant to normalize a GraphQL query and then create a more efficient JSON patch on the server-side. On the client-side, it applies the JSON-patch to the previous normalized result and then deflates it to the "expected" GraphQL result that can be consumed by relay or apollo-client. Ideally, the client only needs to know how to apply JSON patch operations and denormalize (inflate) the result. You could skip the normalization part and create in-efficient patches that send a lot of redundant data to the client (which might be fine since you probably don't have any HTTP overhead for a WebSocket connection), depending on your schema. I realized that having a GraphQL list that changes frequently could result in pretty inefficient patches, which then results in a patch operation that is bigger than the actual query result we are diffing against. In that case, you would probably be better off skipping the JSON patch completely. See the README https://github.com/n1ru4l/graphql-live-queries/pull/40/files#diff-d018057eb168caad73104f87ad8ffca9 for an example. It is also possible to decouple those two parts into denormalization and json-patch generation layers that could be composed. The normalization is not mature enough (that's why I did not merge it yet), it does not handle nested types with field arguments and aliases. All methods have some kind of trade-offs I guess. The idea is to find the best balance. For now, I am more focused on improving query invalidation functionality. As I think fetching some more data isn't a problem in the app I am using this library right now. But this is definitely a thing I wanna get back too once I got some more time. I hope that information was helpful to you! If you have some awesome ideas or even wanna help out, let me know :) |
I started a more generic json patch implementation here: #243 |
@willstott101 Check out https://github.com/n1ru4l/graphql-live-query/tree/main/packages/graphql-live-query-patch This is sufficient for my needs right now, let me know whether this is what you had in mind. For now, I don't plan on applying any further optimizations to the execution result before doing the JSON diffing. |
Yeah that looks nice and simple to me, I think the diffing previous/next is a fine plug and play solution, and json patch libraries clearly make that quite doable. I like the simplicity (assuming what's in the readme is exactly the wire format) of just adding a patch key to the query result. |
The only issue I see right now lists. The patches generated when an item is removed are not so optimal IMHO 😅. It would be nice if json-patch would support some kind of custom object identifier e.g. via The README JSON payloads are examples from actually running the middleware :) |
Yeah that could help, I can see it being tricky to implement without either being excruciatingly slow, or needing some kind of id hint. In many implementations I wonder if it could end up making more sense building the patches manually from events or, depending on the back-end architecture, even from two states as you use the library to do already. I suspect it would be difficult to get anything optimal without building the patches yourself, but the key thing for me is that anyone can find out how to make a json patch, and can test it's doing what they expect. |
Yeah, ideally a fully reactive backend would be the best solution, another solution for reducing the over-head could be to only re-execute partials of a query (and thus only having to diff smaller payloads). Still, that is not optimal for lists, I will do some research for a better list diffing implementation. |
I created #308 for tracking this. |
A library such as https://www.npmjs.com/package/fast-json-patch could be used to only send patches over the network for altering the existing result on the client.
The text was updated successfully, but these errors were encountered: