Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Local state story #24

Closed
rivertam opened this issue Jan 23, 2018 · 18 comments
Closed

Local state story #24

rivertam opened this issue Jan 23, 2018 · 18 comments

Comments

@rivertam
Copy link

Hi I'm a total noob to GraphQL, so I apologize if this is a stupid question, but I'm wondering what the story is for handling local state. I'm used to Redux, which I see is a dependency. However, I've been led to understand that with Apollo 2 comes a discouragement of using Redux alongside for state management, preferring to use https://github.com/apollographql/apollo-link-state. I see #3 exists, the solution to which may be the solution to this issue as well. However, I presume the authors of this library have already considered how users should manage local state, so I'm wondering what the recommended method is. I believe the cache is not to be used for local state, but I could be wrong.

@undefobj
Copy link
Contributor

Hi @rivertam - We don't have any specific recommendation as to how you want to manage your application state, it's up to you as the developer. You could use Redux, Vuex, or even simply setState() in React. While we use Redux Offline as a dependency, that is simply an SDK implementation (the goal is to handle offline persistence and synchronization as well as web socket connections via subscriptions) which you shouldn't base your application layer choices on as it could change based on future requirements.

@nicokruger
Copy link

nicokruger commented Jan 31, 2018

Further to this question, is there anyway to go about disabling the behaviour of caching state to redux? It seems as if in the default configuration, ala:

const apolloClient = new AWSAppSyncClient({ url: appSyncConfig.graphqlEndpoint, apiUrl: appSyncConfig.graphqlEndpoint, region: appSyncConfig.region, auth: { type: appSyncConfig.authenticationType, apiKey: appSyncConfig.apiKey, }});

Keys get created in localStorage, reduxPersist:appsync and reduxPersist:offline that makes me believe that there is at least some default behaviour of trying to use redux for offline caching. Can I turn this off somehow? I am trying to use with Vue and am not using redux, and for now would like to completely disable offline caching and later perhaps use other methods for offline caching.

@rivertam
Copy link
Author

@nicokruger Have you tried using fetchPolicy: 'network-only'?

@jpstrikesback
Copy link

Really interested in using apollo-link-state is that possible?

@nicokruger
Copy link

On the newest version you can use disableOffline: true to turn this off.

Also interested in knowing if we can setup our own links somehow, but if you just want to turn off offline caching altogether disableOffline: true works for now.

manueliglesias added a commit to manueliglesias/aws-mobile-appsync-sdk-js that referenced this issue Apr 16, 2018
Allows the usage of:

- Custom link
- Custom cache
- Custom cache options

Fixes awslabs#3
Fixes awslabs#21
Fixes awslabs#24
Fixes awslabs#36
Fixes awslabs#52
Fixes awslabs#70
Fixes awslabs#87
Closes awslabs#62
@manueliglesias
Copy link
Contributor

manueliglesias commented Apr 17, 2018

Once PR #96 gets merged, it should be possible to use apollo-link-state with the AWS AppSync client like this:

import { ApolloLink } from 'apollo-link';
import { withClientState } from 'apollo-link-state';
import AWSAppSyncClient, { createAppSyncLink, createLinkWithCache } from "aws-appsync";

const stateLink = createLinkWithCache(cache => withClientState({
  cache,
  resolvers: {
    Mutation: {
      updateNetworkStatus: (_, { isConnected }, { cache }) => {
        const data = {
          networkStatus: {
            __typename: 'NetworkStatus',
            isConnected
          },
        };
        cache.writeData({ data });
        return null
      },
    },
  },
  defaults: {
    networkStatus: {
      __typename: 'NetworkStatus',
      isConnected: false
    }
  }
}));

const appSyncLink = createAppSyncLink({
  url: appSyncConfig.graphqlEndpoint,
  region: appSyncConfig.region,
  auth: {
    type: appSyncConfig.authenticationType,
    apiKey: appSyncConfig.apiKey
  }
});

const link = ApolloLink.from([stateLink, appSyncLink]);

const client = new AWSAppSyncClient({}, { link });

const result = await client.mutate({
  mutation: gql`mutation updateNetworkStatus($isConnected: Boolean) {
    updateNetworkStatus(isConnected: $isConnected) @client {
      isConnected
    }
  }`,
  variables: { isConnected: true }
});

console.log(result);

@jpstrikesback
Copy link

Hmm, do these two links use the same cache implicitly somehow??

@jpstrikesback
Copy link

Ok, I think I see here that it's as simple as creating and passing in the same cache:

#96 (comment)

@manueliglesias
Copy link
Contributor

Hey @jpstrikesback

TL;DR

Yeah, in the sample I posted I am using the same cache for both links, although is not very clear.


Long version

To use apollo-link-state you need to use withClientState(), which in turns expects the cache to be passed to it. Now, this is not straightforward in this client, let me elaborate...

When you want to use the offline capabilities of the AppSync client, the client uses its own cache implementation and link chain; it has some internal logic to wait for the cache hydration from the offline storage before processing requests. This means that our cache is initialized asynchronously by the client itself and thus not available for link creation purposes before instantiation of the client.

To give the possibility of creating links that use the cache, a createLinkWithCache helper function is provided. (It will give you access to the same cache instance used internally by the AppSync client and link created by createAppSyncLink )

Its usage looks like this:

const linkThatUsesCache = createLinkWithCache((cache) => new MyLink(cache));

You don't need to pass a cache explicitly to the AWSAppSyncClient constructor (unless you REALLY want to, we don't support offline capabilities when using other cache implementations)

I hope this helps 😃

manueliglesias added a commit that referenced this issue Apr 19, 2018
* Use custom link cache and cache options

Allows the usage of:

- Custom link
- Custom cache
- Custom cache options

Fixes #3
Fixes #21
Fixes #24
Fixes #36
Fixes #52
Fixes #70
Fixes #87
Closes #62

* Pass store to OfflineLink when using createAppSyncLink

* Fix eslint rules violations

* Fix typo. Address CR comment.
@reggie3
Copy link

reggie3 commented Apr 20, 2018

@manueliglesias Is it not required to declare the cache before using it. Such as const cache = new InMemoryCache();

@farzd
Copy link

farzd commented May 1, 2018

@manueliglesias does this mean i can set headers like this ? [thinking of not using cognito and setting/reading JWT from Lambda function etc] will this clash with any of the auth stuff you guys set?

  const authMiddleware = new ApolloLink((operation, forward) => {
    operation.setContext({
      headers: {
        authorization: JWTtoken
      }
    })

    return forward(operation)
  })

//etc
const link = ApolloLink.from([authMiddleware, appSyncLink]);

@honkskillet
Copy link

honkskillet commented May 3, 2018

@farzd I tried your code and I don't seem to be able to set custom headers. Did you figure out how? @manueliglesias
PS I am using AppSync with IAM auth. I really need to just be able to pass the user pool jwt in the headers, but AppSync w/ IAM auth doesn't provide the user pool info.

@farzd
Copy link

farzd commented May 3, 2018

@honkskillet i'm asking a question, not providing a solution. Sorry.

@honkskillet
Copy link

@farzd Yeah. I tried you code and some other similar approaches with composing apollo-link and I haven't been able to get custom headers back to my appSync resolvers. I suspect AppSync is stripping them out?

@farzd
Copy link

farzd commented May 3, 2018

@honkskillet it already attaches a header link: https://github.com/awslabs/aws-mobile-appsync-sdk-js/blob/master/packages/aws-appsync/src/client.js#L51

so not sure what happens if you add it again

Thanks

@fgiarritiello
Copy link

@honkskillet @farzd did you guys find a way to pass the jwt in the header? I'm not interested in cognito or any of the other auth settings provided by appsync.

@farzd
Copy link

farzd commented Jul 17, 2018

@fgiarritiello i haven't looked since unfortunately, let me know if you find something.

@jonlorusso
Copy link

I know it's been a while, but for anyone who stumbles here; This is super hacky, but works (in nodejs):

const Fetch = require('node-fetch')

let token = 'this is my jwt token'
global.fetch = (url, opts) => {
  opts.headers['jwt'] = token
  return Fetch(url, opts)
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants