kamilkisiela / apollo-angular

A fully-featured, production ready caching GraphQL client for Angular and every GraphQL server 🎁
https://apollo-angular.com
MIT License
1.5k stars 311 forks source link

updateQuery error after moving to named clients. #1845

Closed kosso closed 1 year ago

kosso commented 2 years ago

Hi there. I seem to be having an issue since trying to move from a single APOLLO_OPTIONS provider to multiple named APOLLO_NAMED_OPTIONS providers, now that I need to support another HTTP/WSS endpoint.

My initial setup used a split link for HTTPS and WSS to subscribe to a SubGraph:

In app.module.ts:

...
providers: [
    {
      provide: APOLLO_OPTIONS,
      useFactory: createApollo,
      deps: [HttpLink],
    },
]

...

export function createApollo(httpLink: HttpLink): ApolloClientOptions<any> {
  const http = httpLink.create({
    uri: 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2'
  });

  const ws = new WebSocketLink({
    uri: 'wss://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2',
    options: {
      reconnect: true
    }
  });

  const link = split(
    ({ query }) => {
      const data = getMainDefinition(query);
      return (
        data.kind === 'OperationDefinition' && data.operation === 'subscription'
      );
    },
    ws,
    http
  )

  return {
    link: link,
    cache: new InMemoryCache(),
  };
}

All this works fine. In my subgraph service, my query and subscription are all returned and updated ok, using:

const bundle_query = `bundle(id: "1") {
      ethPrice
    }`;
    const init_bundle_query = gql`{
      ${bundle_query}
    }`;
    const sub_eth = gql`subscription bundle{
      ${bundle_query}
    }`;

    this.queryRefEth = this.apollo.watchQuery<any, any>({
      query: init_bundle_query
    });

    this.queryRefEth.subscribeToMore<any, any>({
      document: sub_eth,
      updateQuery: (prev, { subscriptionData }) => {
        if (!subscriptionData.data) {
          return prev;
        }
        const _ethPrice: any = subscriptionData?.data;

        // .... 
      }
    });

But when I attempt to use a named provider (called 'two', but currently set to use the same uris), set up in app.module.ts using:

...
providers: [
    {
        provide: APOLLO_NAMED_OPTIONS,
        useFactory(httpLink: HttpLink): NamedOptions {
            return {
                default: {
                    cache: new InMemoryCache(),
                    link: split(
                        ({ query }) => {
                        const data = getMainDefinition(query);
                            return (
                                data.kind === 'OperationDefinition' && data.operation === 'subscription'
                            );
                        },
                        httpLink.create({
                            uri: 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2',
                        }),
                        new WebSocketLink({
                            uri: 'wss://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2',
                            options: {
                                reconnect: true,
                            },
                        })
                    )
                },
                two: {
                    cache: new InMemoryCache(),
                    link: split(
                        ({ query }) => {
                            const data = getMainDefinition(query);
                            return (
                                data.kind === 'OperationDefinition' && data.operation === 'subscription'
                            );
                        },
                        httpLink.create({
                            uri: 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2',
                        }),
                        new WebSocketLink({
                            uri: 'wss://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2',
                            options: {
                                reconnect: true,
                            },
                        })
                    )
                }
            }
        },
        deps: [HttpLink],
    },
]

and then, in my service, I use the named client 'two' (or using the default):

const bundle_query = `bundle(id: "1") {
      ethPrice
    }`;
    const init_bundle_query = gql`{
      ${bundle_query}
    }`;
    const sub_eth = gql`subscription bundle{
      ${bundle_query}
    }`;

    this.queryRefEth = this.apollo.use('two').watchQuery<any, any>({
      query: init_bundle_query
    });

    this.queryRefEth.subscribeToMore<any, any>({
      document: sub_eth,
      updateQuery: (prev, { subscriptionData }) => {
        if (!subscriptionData.data) {
          return prev;
        }
        const _ethPrice: any = subscriptionData?.data;

        // .... 
      }, onError: err => {
        console.log('updateQuery error:', err);
      }
    });

.. I get an error in updateQuery:

updateQuery error: Error: invalid query: no fields for type `Query`
    at new ApolloError (index.js:29:28)
    at QueryManager.js:494:27
    at Object.next (module.js:305:21)
    at notifySubscription (module.js:132:18)
    at onNotify (module.js:176:3)
    at SubscriptionObserver.next (module.js:225:5)
    at iteration.js:4:68
    at Array.forEach (<anonymous>)
    at iterateObserversSafely (iteration.js:4:25)
    at Object.next (Concast.js:25:43)

I am using "apollo-angular": "^4.1.1" and "@apollo/client": "^3.7.1"

Is there anything I need to change in the construction on my initial query and subscription?

This was also happening in 4.1.0, though I had to use the name 'default' to get the default client. Then I saw the recent fix pushed for that.

Any ideas?

Many thanks!