Apollo-client: Change default fetchPolicy to "cache-and-network"

Created on 22 Aug 2017  路  23Comments  路  Source: apollographql/apollo-client

Hello,

I thought I'd open up this issue for discussion. The current fetchPolicy on GraphQL queries is "cache-first". This default assumes that all mutations are either made by, or can be predicted by the client. I would argue that this isn't true for most web applications.

Defaulting fetchPolicy to "cache-first" opens up the possibility of stale cache reads throughout an app if any queried data has been updated on the server (or by another client) without the client's knowledge. The only way to fix this is to go though your app and mark every query with a more appropriate fetchPolicy (like "cache-and-network").

I think a more sane default for fetchPolicy would be "cache-and-network". In my mind, this gives developers a more predictable experience. If a query result lives in cache, it will be returned while a network round trip takes place. If a developer knows that a query can only be affected by client-initiated changes (which I believe is a more rare use case), they can change their fetchPolicy to "cache-first" for performance gains.

Short of changing the fetchPolicy default value from "cache-first" to "cache-and-network", it might be worth considering making this default value configurable when initializing the Apollo client instance.

Any thoughts? Thanks!

Most helpful comment

hello everyone, i found that it's possible to set it by default:

    const defaultOptions = {
      watchQuery: {
        fetchPolicy: 'cache-and-network',
        errorPolicy: 'all',
      },
      query: {
        fetchPolicy: 'cache-and-network',
        errorPolicy: 'all',
      },
      mutate: {
        errorPolicy: 'all',
      },
    };

    const client = new ApolloClient({
      link,
      cache,
      defaultOptions,
    });

for more: https://www.apollographql.com/docs/react/basics/setup.html#ApolloClient

All 23 comments

I think a default policy of network-only makes more sense. You don't want your application to be storing sensitive information without you specifically setting it to do so.

+1 for allowing the default value to be configurable.

This hasn't been discussed, and consensus hasn't been reached, but I thought I'd throw our a PR for posterity and discussion.

@pcorey what do you think about a way to set defaults for all of the watchQueryOptions? Vue apollo does this and it could be useful for other integrations for it to be part of the core!

@jbaxleyiii Something to consider, for sure.

I haven't dug deep enough to figure out the difference between ModifiableWatchQueryOptions vs the extended WatchQueryOptions, but does it make sense to want to have a global default for things like variables, query, and others?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions to Apollo Client!

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!

+1

any updates on this?

It'd be nice to have the default be configurable indeed!

hello everyone, i found that it's possible to set it by default:

    const defaultOptions = {
      watchQuery: {
        fetchPolicy: 'cache-and-network',
        errorPolicy: 'all',
      },
      query: {
        fetchPolicy: 'cache-and-network',
        errorPolicy: 'all',
      },
      mutate: {
        errorPolicy: 'all',
      },
    };

    const client = new ApolloClient({
      link,
      cache,
      defaultOptions,
    });

for more: https://www.apollographql.com/docs/react/basics/setup.html#ApolloClient

I'm getting an error that says "cache-and-network" can only be used with WatchQuery .. anyone have any ideas for this?

@sajsanghvi for me I just get this error, when I call the query directly with the client, e.g.: this.props.client.query({ query: MyQuery }); (on React).

I agree that cache-first isn't a good default cache policy, but I also have concerns about making cache-and-network the default. This could cause a lot of unnecessary fetching without the user necessarily being aware of it (at least at first)...and it seems to me that the biggest performance gains that can be obtained from caching are from avoiding unnecessary network requests -- not just avoiding unnecessary client-side cache updates. Maybe some sort of time-based caching policy would be a better default. Then in the simplest case, the only configuration tweaking you'd need to do is adjust the amount of time until you consider the cache to be stale and need to re-fetch from the server to check for updates.

I'm assuming that cache-and-network re-fetches the entire query every time and that there aren't any server-side optimizations to avoid re-sending the data when unnecessary. Is that correct?

Too be honest .. Too many network requests is usually a rather positive problem to have... It means that your app have traffic, and you have the resource (time) to look in to increase the caching of static data.A too high cache level would cause more issues with out-of-sync clients, than an over burdened Gateway server.

Most project tends to look in to optimising server performance before caching the client requests since the RoI potential is (generally) greater.

@7ynk3r
You're wrong.
cache-and-network doesn't work with client.query. Only with watchQuery

Error: cache-and-network fetchPolicy can only be used with watchQuery

Docs have changed and there is no mention of fetchPolicy as a default anymore. Can someone confirm a method of setting a default fetchPolicy? I want cache-and-network as a default.

@lukepighetti It doesn't look like defaultOptions works anymore:

image

This is the best way I can think of doing this for the time being:

On my project, I happen to have a LoadingQuery React component that takes care of displaying a spinner for me while a query is running. Because of Query being wrapped in a different component, I have done the following:

function LoadingQuery({ ...props }) {
  return (
    <Query fetchPolicy="network-only" {...props}>
      ...
    </Query>
  );
}

This allows me to default to network-only but also allows for overriding my default because ...props comes AFTER the fetchPolicy prop.

@bsara You need to use apollo-client directly instead of apollo-boost in order to be able to set defaultOptions. There are migration instructions here: https://www.apollographql.com/docs/react/advanced/boost-migration.html

The <Query /> component uses watchQuery so to use network-only by default you should be setting the defaultOptions like this:

const defaultOptions = {
  watchQuery: { fetchPolicy: 'network-only' },
};

const client = new ApolloClient({
  link,
  cache,
  defaultOptions,
})

I know this is a little unrelated to this thread, but the way links to apollo docs constantly expire is really frustrating. The above link doesnt work. This is common in many issue threads.

Does anyone have any reference to why they have chosen the default to be cache-first. This clearly will be the source of many issues for people just getting started with apollo. This doesn't make sense you obviously want to make it easy for beginners and give flexibility for more advanced users.

Was this page helpful?
0 / 5 - 0 ratings