I'm using Apollo to build a production React Native app and I'm super grateful for all the great work you guys have done. Kudos!
There are a couple of things that I think could improve and I know many of them are already in the works (e.g., reimplementing loading logic in react-apollo and restructuring the design around fragments in apollo-client). It's super annoying that loading can be undefined sometimes and it's impossible to work with fragments so I'm looking forward to those changes!
There is another improvement that I wanted to mention because I'm not sure if it is in the works and I would love apollo-client to have something like it.
Imagine you have the following 2 queries:
query ($userId: ID!) {
user(id: $userId) {
name
email
posts {
edges {
node {
title
createdAt
}
}
}
}
}
query ($postId: ID!) {
post(id: $postId) {
title
createdAt
}
}
If the second query returns a post that would've been included in the users's post from the first query, there should be no network request. Currently with apollo-client, because they're different queries, the cache doesn't know any better.
I propose that we add an option to ApolloClient, similar to dataIdFromObject, called queryIdFromObject (this name is probably a bad one) that will let you map the result of a query to another query's key in the internal Redux store, with the purpose of improving the cache.
Here's how the option would be used for the example above:
const client = new ApolloClient({
queryIdFromObject: ({ __typename, id }) => `$ROOT_QUERY.${__typename}:${id}`,
});
Potentially, this option could only be allowed for the root query (I don't see it being beneficial elsewhere) and dataIdFromObject could be used internally so that the code above could be simplified to:
const client = new ApolloClient({
// maybe this name is better?
rootQueryNameFromObject: ({ __typename }) => singularize(__typename.toLowerCase()),
});
Regardless, this would greatly reduce the number of trips to the API that the app needs to make.
Thoughts?
EDIT: If the server is Relay compatible, then it would be even simpler because the relevant root query would be node and/or nodes
This is an interesting idea; maybe instead of mapping a query to a part of another query, instead we should have a mechanism to map to a data id -- so dataIdFromField or something like that.
So in this case, we'd say "the root field post with variable id=X should map to the object with id='post:X'". I'm not sure what the API for that should look like.
@tmeasday,
Yes, that would be a nice way to go about it. Here are 2 possible APIs that we could think about:
updateQueries to the options in client.queryupdateQueries from client.mutate, except that one would be able to update queries from other query results (and not just mutation results)Which of the 2 seems more natural? Should we expand on one over the other or should we expand on both and see which API makes the most sense?
This is now implemented! #809 Just some tests to do.
@stubailo,
Thanks so much for implementing this! Would you mind posting a quick snippet of how the new API could be used to solve the issue mentioned above?
Great! Having this issue as well, the PR would reduce my app's network traffic dramatically. 馃憤
Hoping to get this done and documented before the end of the week! Things have been very busy around here because of the GraphQL Summit.
It looks like this is now documented here. Thanks for all the hard work!
Implemented in #921
Looking again at the original use case presented in the originating issue description, it doesn't look like result reducers solve this problem because the post query has a changing variable (id) and result reducers don't have a way to map the post(id: $postId) back to the internal dataId that the store uses.
@migueloller I'm not sure I understand what result reducers have to do with cache redirects?
@helfer, originally I believed that result reducers would solve the issue I mentioned above in https://github.com/apollostack/apollo-client/issues/706#issue-179112870. It looks like it's more of a cache redirect issue (as you say). Should a separate issue be opened or this same on reopened (and maybe the title changed)?
@migueloller Have you looked at #921? I think that should do what you need.
@helfer, ahh yes... Just read the docs. I initially thought #921 was for result reducers. Sorry about that! 馃槄
Most helpful comment
Hoping to get this done and documented before the end of the week! Things have been very busy around here because of the GraphQL Summit.