Apollo-client: Help improve Apollo Client by contributing use-cases!

Created on 9 Mar 2017  Β·  22Comments  Β·  Source: apollographql/apollo-client

Dear friends, contributors and users,

We've been building Apollo for almost a year now, and we have a pretty good idea what we and the most active contributors need from a good GraphQL client.

However, there are also plenty of use-cases that we think a good GraphQL client should support that we don't have ourselves. We could try to optimize for what we _think_ you want to do with it, but that would only be half as good as building the thing you actually need.

That's where this little project here comes in.

The purpose of this project is to provide a comprehensive set of use cases that a standard GraphQL client like Apollo should support. Every use-case should come from a real world application and be contributed by someone who actually has this very use-cases.

These use cases will help us do three things:
1) Serve as a reference for the full set of real-world use-cases that a good GraphQL client like Apollo (should) support
2) Serve as reference examples of how to accomplish these use-cases in Apollo Client
3) Provide traceability from the use-case to test cases and code.

Apart from guiding the continued development of Apollo Client, it will also enable greater confidence when undertaking refactors, because it will guarantee that all use-cases are clearly documented and easy to find.

We're planning to organize the use-cases neatly in this repository, and let you contribute use-cases via PRs, but while we figure out the best way to do that together with the community, let's use this issue to get the discussion and collection of use-cases started.

Respond to this issue if:

  • You have a currently supported use-case that isn't documented yet (currently all of them)
  • You have a use-case that's not currently supported by Apollo Client
  • You have a use-case that's currently cumbersome to accomplish with Apollo Client
  • You have an idea for a use-case, but you're not quite sure how to formulate it.
  • You have an idea for how to improve the collection or organization of use-cases.
  • You want to write out one of the sample use-cases below in long form

You don't need to have a GraphQL app using Apollo Client in production to contribute a use-case. All you need is a use-case in a real-world application that would benefit from using GraphQL.

Below are some sample use-cases to give you the idea of what we're looking for, but don't let those limit your imagination! If you have an idea that is not along those lines, we definitely want to hear it as well!

Sample use cases:

  • a simple query
  • a simple mutation
  • a simple subscription
  • a kitchen sink of queries (must support any valid GraphQL query)
  • Authenticated transport
  • Retrying on failed requests
  • List query in one view, detail query in the other. Want a subset of info in there.
  • Filling out a form, then submitting that form. Summary data should be available on next page
  • Pagination

    • With cursors

    • Without offset/limit

    • Full on GraphQL connections

  • Reactive data

    • polling

    • subscriptions

    • from other data sources

  • Multi-level pagination
  • State management together with local data
  • Client-only fields (for when you don't control the server)
  • Multiple backends
  • Offline data

    • Cache invalidation

  • Cache consistency after mutations

    • by refetching (the lazy way)

    • by updating the cache in a fine-grained manner

  • Performance

    • Large queries

    • Large responses

    • Deep nesting

    • Large arrays

    • Lots of queries

    • Lots of responses

  • Future use-cases

    • live, defer, stream

πŸ™ help-wanted

Most helpful comment

I wish this could be a poll of sorts, where you can tick off the things you are doing.

Things I actually do:

  • Queries:

    • I use static queries, so persistent queries would be nice.

    • Reading a large (100s) array of unique-id items into browser memory for instant search and for translations. Items are small-ish objects with maybe an embedded array or two.

    • Reading full detail for existing objects. 50 fields, with some of them embedded objects or arrays. If the embedded objects don't have ids, they are part of the parent object.

    • Using reselect to derive data from the query results

    • Pagination:



      • limit, cursor


      • I have a type creator for paging, <Type> => {items: [<Type>], cursor: ID}


      • My database returns queries in this format; cursor is an opaque value you can pass to the query to continue searching (it requires requested sorting to remain the same between queries).


      • This can do multi-level but have not had a need yet.



  • Mutations:

    • Updating single objects with unique ids, I fetch all the fields after a mutation so all queries are correctly updated.

    • Deleting single objects with ids. It would be awesome if there was some way to tell A-C about that instead of having to filter arrays myself.

    • Creating single objects with ids. This is rare enough for me that I don't mind refetching the queries that have that object, by default. Would be great if A-C could (semi-)automatically see which cached queries can have the created object as a result and mark them dirty/refetch if active.

    • Uploads:

    • Currently upload out-of-band and use the resulting token to refer to uploads

  • Authentication: erm, not yet. Will use Express sessions and some sort of login, maybe over graphql. context will have auth data.
  • Server/connectivity:

    • Apollo Express server with batching, and hot reload for resolvers

    • Wish to use websocket transport to avoid session setup on each query but not there yet.

    • Define schemas in object language so I can create types on-the-fly

    • Automatically created: i18n objects with all the configured languages, paginated types

NOT using optimistic results yet.

Right now, cache performance is truly terrible for me. See #1300.

I will respond on the react-apollo issue for more specifics on how I use it.

All 22 comments

@helfer want me to write about Large queries and Large Responses? haha.

@thebigredgeek sure, that would be great! I think @wmertens might also have a thing or two say about that.

I wish this could be a poll of sorts, where you can tick off the things you are doing.

Things I actually do:

  • Queries:

    • I use static queries, so persistent queries would be nice.

    • Reading a large (100s) array of unique-id items into browser memory for instant search and for translations. Items are small-ish objects with maybe an embedded array or two.

    • Reading full detail for existing objects. 50 fields, with some of them embedded objects or arrays. If the embedded objects don't have ids, they are part of the parent object.

    • Using reselect to derive data from the query results

    • Pagination:



      • limit, cursor


      • I have a type creator for paging, <Type> => {items: [<Type>], cursor: ID}


      • My database returns queries in this format; cursor is an opaque value you can pass to the query to continue searching (it requires requested sorting to remain the same between queries).


      • This can do multi-level but have not had a need yet.



  • Mutations:

    • Updating single objects with unique ids, I fetch all the fields after a mutation so all queries are correctly updated.

    • Deleting single objects with ids. It would be awesome if there was some way to tell A-C about that instead of having to filter arrays myself.

    • Creating single objects with ids. This is rare enough for me that I don't mind refetching the queries that have that object, by default. Would be great if A-C could (semi-)automatically see which cached queries can have the created object as a result and mark them dirty/refetch if active.

    • Uploads:

    • Currently upload out-of-band and use the resulting token to refer to uploads

  • Authentication: erm, not yet. Will use Express sessions and some sort of login, maybe over graphql. context will have auth data.
  • Server/connectivity:

    • Apollo Express server with batching, and hot reload for resolvers

    • Wish to use websocket transport to avoid session setup on each query but not there yet.

    • Define schemas in object language so I can create types on-the-fly

    • Automatically created: i18n objects with all the configured languages, paginated types

NOT using optimistic results yet.

Right now, cache performance is truly terrible for me. See #1300.

I will respond on the react-apollo issue for more specifics on how I use it.

BTW batching really helped when I am loading data per table row. However, a websocket transport would have the same result I think.

If I understood correctly what is this post about then I am currently facing use case I am unable to solve relevant issue. If you guys point me in the right direction and I actually solve it :smile: I could write something about it

@kolpav yes, your use-case might be very interesting to inform others about patterns to use for representing nested information! If you could describe it (and the solution) succinctly here, that would be great!

@helfer As you can check in an email I sent you, my current use case not supported by Apollo Client is:

1 - Send queries and mutations over an websocket auth connection using an auth token. (There is no default network interface for websocket connection at the moment).

2- Use the same websocket connection to also listen for subscriptions (currently subscriptions-transport-ws don't support receiving an already opened websocket to using. It always open a new websocket)

@mistic Yeah, that's a use-case we'd like to support very soon. @DxCx has already been working on it for a bit. The current plan is to add capability for queries and mutations to subscriptions-transport-ws and rename it to graphql-transport-ws or something. You should check in with him and @Urigo so you guys don't duplicate work! πŸ™‚

Use case for https://github.com/apollographql/react-apollo/issues/472:

Maybe I'm doing it wrong, but in my app I have the following pattern a lot:

@graphql(someQuery)
class Viewer extends Component {
  handleAction = () => {
    // somehow get different data from the query using different variables
    // e.g. search by a category
  }
…
}

With react-apollo not allowing internal state on the query, this becomes at least

@connect(selectVariablesForSearch, {setSearch})
@graphql(someQuery)
class Viewer extends Component {
  handleAction = () => {
    this.props.setSearch({…})
  }
…
}

So now, for a simple internal-state search, I need to add a reducer and an action for every time I encounter this pattern. I think it would be nicer to just use this.props.data.setVariables.

Hey @helfer I already sent an email to @Urigo to check this situation with him. However, do u have any estimative of the time needed to have graphql-transport-ws implemented in an alpha version? I can give some help with it :)

Regarding query options: when you need to pass certain context values as query variables, rather than props, there is currently no straightforward way to do so. It would be nice if context was passed to the options argument of the HOC. Like so:

const ProfileWithData = graphql(CurrentUserForLayout, {
  options: (ownProps, ownContext) => ({ variables: { foo: ownContext.foo } }),
})(Profile);

Cache staleness. I have a React Native app. If a user leaves the app running in the background for a day and reopens it, I'd like Apollo to refetch. Or if they jump to a page for which the data is already loaded after returning from a long break, I want Apollo to realise the cache is old and refetch.

If we could set an argument to the client saying the cache is old after 5 minutes that would be great.

I know I can use polling to keep things fresh, but that's not what I'm looking for. I don't want apps polling the servers constantly. I just want one refresh of the data after some amount of time of being idle.

@elie222, try 'resetStore'?

Good idea. Do a resetStore after a certain timeout. Thanks.

Would be cool if you could do it on a per query basis. You probably can I'm
guessing would just start to get complicated.

On 8 Apr 2017 23:45, "Andrew E. Rhyne" notifications@github.com wrote:

@elie222 https://github.com/elie222, try 'resetStore'?

β€”
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/apollographql/apollo-client/issues/1391#issuecomment-292744436,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AC8oXys2lQmydzaLGmWmx7mxnqm_1xG9ks5rt_HLgaJpZM4MYf8R
.

You might be able to hook into some sort of event with react native for "resume". Use an interval to persist the time into phone storage (which should pause when the app is sent to background) and then on resume check and diff that against the current time. If it's past a certain threshold, reset the store

That said, a per-query staleness setting would be nice. With REST, you can
use caching headers.

But in fact, the whole caching layer assumes that everything is an object
with a unique id, and that's not generally true.

On Sun, Apr 9, 2017, 12:03 AM Andrew E. Rhyne notifications@github.com
wrote:

You might be able to hook into some sort of event with react native for
"resume". Use an interval to persist the time into phone storage (which
should pause when the app is sent to background) and then on resume check
and diff that against the current time. If it's past a certain threshold,
reset the store

β€”
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/apollographql/apollo-client/issues/1391#issuecomment-292748728,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AADWljY3KwLHeG3IbRYhFEgUaki8_1XQks5ruAQkgaJpZM4MYf8R
.

Also, thinking about this a little more. It's even more of an issue on web.
If a user leaves a tab open and returns after 5 hours, I'd expect that when
the user goes to a new page Apollo reloads the data.

If Apollo can track how long ago it last queried the server for every
query, then it should be fairly simple for Apollo to automatically refetch
after a certain amount of time and avoid cache staleness.

Without this it will be a very strange user experience for users of single
page apps.

On 9 April 2017 at 09:04, Wout Mertens notifications@github.com wrote:

That said, a per-query staleness setting would be nice. With REST, you can
use caching headers.

But in fact, the whole caching layer assumes that everything is an object
with a unique id, and that's not generally true.

On Sun, Apr 9, 2017, 12:03 AM Andrew E. Rhyne notifications@github.com
wrote:

You might be able to hook into some sort of event with react native for
"resume". Use an interval to persist the time into phone storage (which
should pause when the app is sent to background) and then on resume check
and diff that against the current time. If it's past a certain threshold,
reset the store

β€”
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
issues/1391#issuecomment-292748728>,
or mute the thread
AADWljY3KwLHeG3IbRYhFEgUaki8_1XQks5ruAQkgaJpZM4MYf8R>
.

>

β€”
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/apollographql/apollo-client/issues/1391#issuecomment-292766370,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AC8oX0ngKOsrSs9FFjaScXtjI24uXhLkks5ruHT1gaJpZM4MYf8R
.

@wmertens I think the cache control could be partially handled by a pluggable cache interface. You could implement and plug in a "no-op" cache interface if you don't want caching, for instance.

yes, but still, cache in-alidation is the hard thing, and everybody writing
their own won't help…

On Mon, Apr 10, 2017, 6:41 PM Andrew E. Rhyne notifications@github.com
wrote:

@wmertens https://github.com/wmertens I think the cache control could
be partially handled by a pluggable cache interface. You could implement
and plug in a "no-op" cache interface if you don't want caching, for
instance.

β€”
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/apollographql/apollo-client/issues/1391#issuecomment-293007201,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AADWlvESAIHddXNuZkCMdQztrV02GiSVks5rulurgaJpZM4MYf8R
.

@wmertens yeah it can definitely be challenging, but there are already so many patterns for cache handling server-side. I think we could use some of those to be honest. The difficult part, to me, is how to propagate cache invalidation to downstream modules that depend on state that exists in the cache... not so much the cache invalidation mechanism itself.

This issue has been automatically closed because it has not had recent activity after being marked as stale. If you belive this issue is still a problem or should be reopened, please reopen it! Thank you for your contributions to Apollo Client!

@helfer are still parts of it relevant, also regarding of caching with Apollo? I am searching for a master thesis topic, and I thought of writing about caching with GraphQL on the client side. It might be a good opportunity to research about caching behaviors and different practices with GraphQL. At the end I thought of implementing my results into Apollo, if the results are valuable for the project.

Was this page helpful?
0 / 5 - 0 ratings