Notes moved from graph-gophers/graphql-go#15
Graphql-js can parse directives like @live
just fine -
parsed.definitions[0].selectionSet.selections[0].selectionSet.selections[0].directives[0] =
{ kind: 'Directive',
name: { kind: 'Name', value: 'live', loc: { start: 26, end: 30 } },
arguments: [],
loc: { start: 25, end: 30 } }
So, we can write things like this:
{
likeCount @live
}
The question then is how the data is returned. This is more of a client question - I plan to patch this stuff into apollo-client
. Apollo client and relay both have internal caches / stores. A query looks like this:
- Parse the query
- Transform it (remove unnecessary / cached fields, add
__typename
) - Send the query to the server (
graphql-go
) - Receive the response, parse it, apply changes to the internal cache
- Rebuild the response data using the original user-supplied query, and the cache as the datastore.
- Deliver the data back to the user.
Right now responses look like this:
{
"data": {
"regions": [
{
"__typename": "Region",
"id": "av1",
"ipRange": {
"__typename": "IPRange",
"ip": {
"__typename": "IPAddress",
"address": [
10,
110,
1,
0
]
},
"plen": 24
},
"location": {
"__typename": "GeoLocation",
"latitude": 40.4257789,
"longitude": -86.9193591
},
"name": "Anvil",
"zoomlevel": 16
}
],
}
With an @live
we would expect realtime updates to come back. With @defer
, you would initially ignore the @defer
-red fields and return without them, then later send the data back in a separate message. Facebook's proposed "patch" message would look like this:
{
"path": ["feed", "stories", 0, "comments"],
"data": [{
"name": "tester",
"comment": "test"
}]
}
I would argue more for something like my json-mutate package, where you can do more granular updates of messages if they change. But perhaps adhering to Facebook's style is better, as they seem to already be using it in production and probably won't want to change down the line.
So, as far as I can tell the things that need to be done here to support this (experimentally!) are:
- Graphql-js already supports the directives
- Assess graphql-go's directive parser and see if anything needs to be done there (done)
- Add the relevant code to
apollo-client
to:- Handle long-term queries and provide an API handle to cancel / terminate them (or do so automatically)
- Batch together
@defer
and@live
queries to avoid duplicate streams of data - Add a NetworkInterface to support live queries
- Decide on a format for the patch messages and add a mechanism to process them + apply them to the cache. Apollo's existing code should be capable of handling updates to the cached data and communicating these updates back to the UI code.
- Add the relevant code to
graphql-go
to handle these types of queries.
In terms of graphql-go - I think for "defer" we can implement it without any changes to the resolver function pattern. Instead of waiting for all of the resolvers to finish, we can instead just wait for the required ones, and then send back the response immediately and send patches later as the resolvers finish
For @live
and subscriptions, we already have Context
in the resolver functions. I think the difference here is, we need to return something like a channel from the resolver. When the query is terminated, the context will be canceled. If the resolver needs to stop sending data, it can close the channel, and optionally send an error down the channel just before doing that.
Shouldn't be too difficult! :)
I've moved effort on this to my RealTime GraphQL project.