Aws-mobile-appsync-sdk-js: apollo_cache_inmemory_1.readQueryFromStore is not a function in browser

Created on 6 Nov 2018  ยท  16Comments  ยท  Source: awslabs/aws-mobile-appsync-sdk-js

Do you want to request a feature or report a bug?
bug

What is the current behavior?
I'm receiving an error message when trying to process an offline query

ERROR Error: Network error: apollo_cache_inmemory_1.readQueryFromStore is not a function
    at new ApolloError (ApolloError.js:37)
    at QueryManager.js:335
    at QueryManager.js:710
    at Array.forEach (<anonymous>)
    at QueryManager.js:709
    at Map.forEach (<anonymous>)
    at QueryManager.push../node_modules/aws-appsync/node_modules/apollo-client/core/QueryManager.js.QueryManager.broadcastQueries (QueryManager.js:704)
    at QueryManager.js:284
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:388)
    at Object.onInvoke (core.js:3824)

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem.
It happens from time to time, only when a query is executed and the store is offline, well, only when my code reaches method processOfflineQuery.

What is the expected behavior?
Process the query.

Which versions and which environment (browser, react-native, nodejs) / OS are affected by this issue? Did this work in previous versions?
I'm using, in a angular app in browser (chrome):

    "apollo-angular": "^1.5.0",
    "apollo-angular-link-http": "^1.4.0",
    "apollo-cache-inmemory": "^1.3.9",
    "apollo-client": "^2.4.3",
    "apollo-link-error": "^1.1.1",    
    "aws-appsync": "^1.4.0",

The store should be hydrated since I do it in app startup.

Thank you

bug offline

Most helpful comment

@jamesalexmorgan @e23z @luccamordente @iudelsmann

We just published a new version to npm, could you guys test with these:

All 16 comments

Can you provide a code sample of how you're referencing the Apollo store and running a query when offline?

Hello @undefobj . I'm not really offline, but it does evaluate my store as offline on const { offline: { online } } = this.store.getState(); (in offline-link.ts).

I'm configuring the appsync client and Apollo by calling this method on app startup:

hydrated() {
    const config = {
      url: appSyncConfig.graphqlEndpoint,
      region: appSyncConfig.region,
      auth: {
        type: appSyncConfig.authenticationType,
        apiKey: appSyncConfig.apiKey,
      },
      complexObjectsCredentials: null,
      offlineConfig: {
        storage: localForage,
      },
      // disableOffline: true,
    };

    const redirectLink = onError(({ networkError }) => {
     [...]
    });

    const options = {
      link: redirectLink.concat(
        createAppSyncLink({
          ...config,
          resultsFetcherLink: ApolloLink.from([
            setContext((request, previousContext) => ({
              headers: {
                ...previousContext.headers,
                'x-csrf-token': this.authService.token,
              },
            })),
            createHttpLink({
              uri: config.url,
              credentials: 'include', // include cookies in the request
            }),
          ]) as HttpLink,
        })
      ),
    };

    const client = new AWSAppSyncClient(config, options);

    this.apollo.setClient(client as any);
    return client.hydrated();
  }

In app.module.ts:

providers: [
[...]
    {
      provide: APP_INITIALIZER,
      useFactory: (service: AppsyncService) => () => service.hydrated(),
      deps: [AppsyncService, MatSnackBar],
      multi: true,
    },
[...]
]

And calling queries and mutations using angular services as documented here

Are you trying to use the AppSync SDK to connect to a non AppSync endpoint?

There is an API Gateway in front of the appsync, only to perform authentication. It's just a proxy, that uses a custom authorizer before forwarding the request.

I'm seeing pretty much this exact behavior in a react-native app as well. Using the demo app from here: https://docs.aws.amazon.com/appsync/latest/devguide/building-a-client-app-reactnative.html. It appears the error is thrown but the query is still executed against the offline cache and returning results.

Ok this makes more sense now. The subscriptions have a handshake process that is roughly:

  • GraphQL subscription statement goes over HTTP
  • Service takes this and computes the appropriate partitioning for different requests, including any runtime arguments in the subscription document
  • Connection metadata is returned to the client
  • Client uses the connection metadata to setup appropriate websocket connections based on the backend partitioning scheme

You're probably failing on that last step. Placing an intermediary in front of the service for this isn't really supported at this time, so I'm not exactly sure what guidance to give you here. You might need to do a bit of trial/error without that endpoint or just perform your own authorization in AppSync. If you are wedded to using a Lambda in front of your requests for GraphQL authorization you might try something like this: https://hackernoon.com/graphql-authorization-with-multiple-data-sources-using-aws-appsync-dfae2e350bf2

This does make some sense, but it's too big of a change for me to do it now to validate. Anyhow thanks, never knew we could use lambda authentication inside AppSync, very intresting.

It also seems I'm not the only one with this issue, but I doubt many are using an api gateway as proxy like myself. I'll keep trying to get more details on the problem and post here any findings.

I'm having the same issue, as @RocketPuppy.

But in my case it happens only when I first load the app in Safari (easier to reproduce with private browsing enabled).

As soon as I hit reload, everything comes back just fine.
Any ideas?

Anyone had success on solving this? Tried everything and couldn't fix it so far. :/

Hi @e23z @luccamordente @iudelsmann we believe there might be an issue with a dependent package causing this issue which had a breaking change. We're currently investigating and will report back when we have a mitigation.

@undefobj thanks for looking into this legends! My current scenario involves firing the query manually, and I can replicate the issue about 50% of the time with my setup...

import client from './graphqlClient';
import gql from 'graphql-tag';
...
const data = await client.query({
  query: gql`
    query CurrentUser {
      currentUser {
        user_id
        user_type
        user_name_first
        user_name_last
        user_company_id {
          company_id
          company_name
        }
      }
    }
  `,
  fetchPolicy: 'network-only',
});

I just upgraded some packages to the latest...
"apollo-link": "^1.2.2",
"apollo-link-error": "^1.0.9",
"aws-amplify": "^1.1.10",
"aws-appsync": "^1.4.0",
"aws-appsync-react": "^1.2.0",
"react-apollo": "^2.3.1",

If it helps.

Many thanks awesome appsync team!! You're smashing it! ๐Ÿ˜„

@jamesalexmorgan @e23z @luccamordente @iudelsmann

We just published a new version to npm, could you guys test with these:

@manueliglesias Can't replicate the issue anymore!!! ๐Ÿ˜† ๐ŸŽ‰ ๐Ÿ˜† ๐ŸŽ‰ ๐Ÿ˜† ๐ŸŽ‰ ๐Ÿ˜† ๐ŸŽ‰
You guys are awesome!!

@manueliglesias Thanks a lot! You guys are amazing! The issue is completely gone. :D

The only problem I am facing now is this:

Error: Network error: Can't find field listPostTypes({"limit":10}) on object undefined.
ApolloError โ€” ApolloError.js:58
(anonymous function) โ€” QueryManager.js:522
(anonymous function) โ€” QueryManager.js:982
forEach
(anonymous function) โ€” QueryManager.js:981
forEach
broadcastQueries โ€” QueryManager.js:977
(anonymous function) โ€” QueryManager.js:477
promiseReactionJob

But it's probably some mistake I've made or something I misconfigured. And a simple setTimeout workaround to delay my query fixed the problem anyway.

You're fast! Thanks for that.

Same as @e23z here. Same replication steps as well.

I've just updated to these versions:
[email protected]
[email protected]

No more errors for me. Thank you very much!

Was this page helpful?
0 / 5 - 0 ratings