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

Mutations fail using aws-appsync with @apollo/react-hooks 3.0.0 #450

Open
richblend opened this issue Aug 8, 2019 · 51 comments
Open

Mutations fail using aws-appsync with @apollo/react-hooks 3.0.0 #450

richblend opened this issue Aug 8, 2019 · 51 comments
Labels
Apollo appsync-core Related to core updates within AppSync SDK React Issues in regards to React and AppSync SDK to-be-reproduced We need to reproduce this issue

Comments

@richblend
Copy link

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

What is the current behavior?
When performing a mutation whilst online, the promise never resolves, and the mutation just hangs.

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem.

We are starting to use @apollo/react-hooks 3.0.0 since the previous hook library we were using has been deprecated and has a bug. This has a dependency on apollo-client 2.6.3, which is not compatible with aws-appsync.

To fix this, we are forcing resolutions in npm to fix the version across libraries:

"resolutions": {
    "apollo-client": "2.6.3"
  }

The app compiles and runs ok. Queries work fine, but the mutations hang.

To make sure the problem doesn't lie with react-hooks lib, i tried mutating using the client directly:

console.log('mutating...')
const result = await client.mutate({
  mutation: MUTATION,        
  variables: {
    forename: 'test value',
  },
})
console.log('result', result)

What is the expected behavior?

Mutations should work as normal

Which versions and which environment (browser, react-native, nodejs) / OS are affected by this issue? Did this work in previous versions?

@apollo/react-hooks 3.0.0
aws-appsync 1.7.2
apollo-client 2.6.3

@bduff9
Copy link

bduff9 commented Aug 14, 2019

Just ran into this after spending 2 days migrating to the new version, a fix or workaround would be much appreciated as this is preventing us from updating our production app.

@tjhowe
Copy link

tjhowe commented Aug 15, 2019

@bduff9 We had the same situation!

@bduff9
Copy link

bduff9 commented Aug 15, 2019

Not to stir the pot, but seeing as how we need to decide on a solution within the next 24 hours, we are deciding if we want to revert 2 days of work and just eat that time, or replace appsync sdk with plain apollo client. Seeing as how we're not using the react appsync package at all, the biggest thing would be what we would be giving up if we did.

Most offline things seem to be able to be handled with relative ease with other packages, and we can handle auth manually. Does anyone know what else we might be giving up by removing this dependency from our react app to get around this issue?

EDIT: Nevermind, I see now that appsync uses MQTT instead of the websockets that apollo supports. Guess we'll need to start reverting all changes.

@asnaseer-resilient
Copy link

Support for @apollo/react-hooks 3.0.1 or greater would be greatly appreciated as the hooks simplify a lot of boiler plate code. Is there any ETA on when this will be supported?

@TeoTN
Copy link

TeoTN commented Aug 17, 2019

I also have this problem. It's quite disappointing to see it failing even though react-apollo v3 was in public beta for about two months now...
Likely, the issue is related to offline functionality since passing disableOffline = true in client's options and providing custom Rehydrate makes them work again

@TeoTN
Copy link

TeoTN commented Aug 28, 2019

I wonder if there's any ETA for solution of this issue?

@nc9
Copy link

nc9 commented Sep 9, 2019

here is my temporary solution, switching to ApolloProvider and setting it up to use the link from AppSync

import { Auth } from "aws-amplify"
import { createAppSyncLink } from "aws-appsync"
import awsconfig from './aws-exports'
import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';

const httpLink = createHttpLink({
  uri: awsconfig.aws_appsync_graphqlEndpoint,
});

const awsLink = createAppSyncLink({
  url: awsconfig.aws_appsync_graphqlEndpoint,
  region: awsconfig.aws_appsync_region,
  auth: {
    type: awsconfig.aws_appsync_authenticationType,
    credentials: () => Auth.currentCredentials(),
    jwtToken: async () =>
      (await Auth.currentSession()).getAccessToken().getJwtToken()
  },
  complexObjectsCredentials: () => Auth.currentCredentials()
 })

export default new ApolloClient({
  link: awsLink.concat(httpLink),
  cache: new InMemoryCache()
});

@isocra
Copy link

isocra commented Sep 9, 2019

@nc9 Does this work offline? I've got a React Native mobile app and I need the offline capability and ideally a more persistent cache than an InMemoryCache as I don't want to lose mutations that haven't made it to the server yet if the app crashes

@nc9
Copy link

nc9 commented Sep 10, 2019

@isocra it should - it is doing what AppSync is building within it's own client class but skipping Rehydrate and the observable there which is causing issues but I haven't tested it

ideally a more persistent cache than an InMemoryCache as I don't want to lose mutations that haven't made it to the server yet if the app crashes

You can build the ApolloClient class in whichever way would suit such as apollo-cache-persist with AsyncStorage support for Native from here

from the example:

const cache = new InMemoryCache({...});

await persistCache({
  cache,
  storage: AsyncStorage,
})

export default new ApolloClient({
  link: awsLink.concat(httpLink),
  cache,
});

even with this issue fixed I believe we're going to stick to using AppSync in this way because we've had too many issues with the layer of abstraction ontop of Apollo and benefiting from new releases

@ryanwalters
Copy link

@nc9 Great solution! This saved the day for us. Do you happen to know if there is any additional configuration needed to get this working with subscriptions?

@superjose
Copy link

Temporary hack:
apollographql/react-apollo#3148 (comment)

Here's step by step:

Force appsync to resolve to apollo-client 2.6.3 or greater (2.6.4 works as of this writing).
If you're using Yarn, add in your package.json a resolutions key and add apollo-client:2.6.4.

Then run yarn install. (If that didn't work, try deleting the node_modules folder first).

If you're using npm, then you will have to patch the package-lock.json. You can do this with npm-force-resolutions.

Add in resolutions "apollo-client": "2.6.4" into package.json

  "scripts": {
      ....
  },
  "browserslist": [
       ...
  ],
  "dependencies": {
    "@apollo/react-hooks": "^3.1.0",
    "aws-appsync": "^2.0.0",
    "aws-appsync-react": "^2.0.0",
  },
  "devDependencies": {
     "typescript": "^3.6.3"
  },
  "resolutions": {
    "apollo-client": "2.6.4"
  }

Delete the entire node_modules folder, and then run:
npx npm-force-resolutions

This will force all the dependencies inside package.json to reference the apollo-client package correctly.

And then:
npm install

@stewartduffy
Copy link

@nc9 this looks promising - Any chance you could post up how you are using the Client? Do you just import it and pass it to the ApolloProvider from the hooks package like this?
<ApolloProvider client={client}> the reason I ask is mine seems to be making the request fine but getting a 401 unauthorised and the auth headers aren't being sent.

@ph0ph0
Copy link

ph0ph0 commented Sep 23, 2019

I am also facing the same problem as @stewartduffy so if anyone finds a solution, please post as I need this rectified urgently!!!

@arantespp
Copy link

arantespp commented Sep 23, 2019

I know this isn't the best solution ever, but the one I'm using allows me to use AWS AppSync with
@apollo/react-hooks 3.0.0 because resolutions didn't work for me.

Instead I use useQuery or useMutation, I'm using useApolloClient and performing queries and mutations directly from client object. So when AWS AppSync supports Apollo 3.0.0, I just refactor my hooks keeping the same returned object.

export const useGetProjectsNames = (userId: string) => {
	const client = useApolloClient();
	const [state, setState] = useState({
		loading: true,
		projects: [],
	});

	useEffect(() => {
		client
			.query({
				query: projectsNamesQuery,
				variables: { userId },
			})
			.then(({ data, errors }) => {
				if (errors) {
					setState({ loading: false, error: errors[0].message, projects: [] });
				}

				setState({ loading: false, projects: data.allProjects });
			})
			.catch(err =>
				setState({ loading: false, error: err.message, projects: [] })
			);
	}, []);

	return state;
};

I hope it helps someone!

@nagad814
Copy link

I think for a paid solution like AppSync, should not need so much hacking. I have tried all the above solutions but still facing issues. I am reverting apollo to a compatible version.

@doldyn
Copy link

doldyn commented Oct 5, 2019

We have now explored this issue further. The reason to use AppSync over just the ApolloClient is if you need the offline capability. We wrote our own Rehydrated and got around the issues there but then when posting a mutation, it got enqueued in redux-offline but never processed. We debugged the flow and found the issues to be in the offline-link created redux-offline effect.

AppSync is using a method called client.queryManager.buildOperationForLink that no longer exists to create the observable and hence nothing happens when redux-offline calls the effect.

We refactored this to the following construct using the same approach as Apollo does in the mutations:

        client.queryManager.getObservableFromLink(
            mutation,
            extraContext,
            variables,
            false,
        ).subscribe({            
            next: data => {...

There were a few other minor issues that we have been changing to make the framework work for our specific use case but this is the key one the core framework falls over on.

We now have this working nicely with hooks and our adapted version of AppSync for our use case and I just wanted to share in case anyone else are looking to do the same or if this could inspire the core team to update the framework as it is a hinderance for adaptation.

@sakhmedbayev
Copy link

sakhmedbayev commented Oct 9, 2019

Has anyone worked out a solution for SSR? I am using AppSync with Next.js. A solution found here https://github.com/dabit3/next-apollo-appsync works with Apollo render props, NOT with hooks, however :-(.

Here is how I am trying to initialize ApolloClient (it works only on the client-side, the server stucks at loading: true state):

import { ApolloProvider } from "@apollo/react-hooks";
import { awsmobile } from "@teloscom/ecomapiawsamp";
import { InMemoryCache } from "apollo-cache-inmemory";
import { ApolloClient } from "apollo-client";
import { createHttpLink } from "apollo-link-http";
import Amplify, { Auth } from "aws-amplify";
import { AUTH_TYPE, createAppSyncLink } from "aws-appsync";
import fetch from "isomorphic-unfetch";
import Head from "next/head";
import React from "react";

Amplify.configure({
  ...awsmobile
});

// Polyfill fetch() on the server (used by apollo-client)
if (!process.browser) {
  global.fetch = fetch;
}

let apolloClient = null;

/**
 * Creates and provides the apolloContext
 * to a next.js PageTree. Use it by wrapping
 * your PageComponent via HOC pattern.
 * @param {Function|Class} PageComponent
 * @param {Object} [config]
 * @param {Boolean} [config.ssr=true]
 */
export function withApollo(PageComponent, { ssr = true } = {}) {
  const WithApollo = ({ apolloClient, apolloState, ...pageProps }) => {
    const client = apolloClient || initApolloClient(apolloState);
    return (
      <ApolloProvider client={client}>
        <PageComponent {...pageProps} />
      </ApolloProvider>
    );
  };

  // Set the correct displayName in development
  if (process.env.NODE_ENV !== "production") {
    const displayName =
      PageComponent.displayName || PageComponent.name || "Component";

    if (displayName === "App") {
      console.warn("This withApollo HOC only works with PageComponents.");
    }

    WithApollo.displayName = `withApollo(${displayName})`;
  }

  if (ssr || PageComponent.getInitialProps) {
    WithApollo.getInitialProps = async ctx => {
      const { AppTree } = ctx;

      // Initialize ApolloClient, add it to the ctx object so
      // we can use it in `PageComponent.getInitialProp`.
      const apolloClient = (ctx.apolloClient = initApolloClient());

      // Run wrapped getInitialProps methods
      let pageProps = {};
      if (PageComponent.getInitialProps) {
        pageProps = await PageComponent.getInitialProps(ctx);
      }

      // Only on the server:
      if (typeof window === "undefined") {
        // When redirecting, the response is finished.
        // No point in continuing to render
        if (ctx.res && ctx.res.finished) {
          return pageProps;
        }

        // Only if ssr is enabled
        if (ssr) {
          try {
            // Run all GraphQL queries
            const { getDataFromTree } = await import("@apollo/react-ssr");
            await getDataFromTree(
              <AppTree
                pageProps={{
                  ...pageProps,
                  apolloClient
                }}
              />
            );
          } catch (error) {
            // Prevent Apollo Client GraphQL errors from crashing SSR.
            // Handle them in components via the data.error prop:
            // https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-query-data-error
            console.error("Error while running `getDataFromTree`", error);
          }

          // getDataFromTree does not call componentWillUnmount
          // head side effect therefore need to be cleared manually
          Head.rewind();
        }
      }

      // Extract query data from the Apollo store
      const apolloState = apolloClient.cache.extract();

      return {
        ...pageProps,
        apolloState
      };
    };
  }

  return WithApollo;
}

/**
 * Always creates a new apollo client on the server
 * Creates or reuses apollo client in the browser.
 * @param  {Object} initialState
 */
function initApolloClient(initialState) {
  // Make sure to create a new client for every server-side request so that data
  // isn't shared between connections (which would be bad)
  if (typeof window === "undefined") {
    return createApolloClient(initialState);
  }

  // Reuse client on the client-side
  if (!apolloClient) {
    apolloClient = createApolloClient(initialState);
  }

  return apolloClient;
}

/**
 * Creates and configures the ApolloClient
 * @param  {Object} [initialState={}]
 */
function createApolloClient(initialState = {}) {
  const ssrMode = typeof window === "undefined";
  const cache = new InMemoryCache().restore(initialState);

  const httpLink = createHttpLink({
    uri: awsmobile.aws_appsync_graphqlEndpoint
  });

  const awsLink = createAppSyncLink(
    {
      url: awsmobile.aws_appsync_graphqlEndpoint,
      region: awsmobile.aws_appsync_region,
      auth: {
        type: AUTH_TYPE.AWS_IAM,
        credentials: () => Auth.currentCredentials(),
        jwtToken: async () =>
          (await Auth.currentSession()).getAccessToken().getJwtToken()
      },
      complexObjectsCredentials: () => Auth.currentCredentials(),
      disableOffline: true
    },
    { ssrMode }
  );

  const client = new ApolloClient({
    link: awsLink.concat(httpLink),
    cache: new InMemoryCache(),
    ssrMode
  });

  return client;
}

@sakhmedbayev
Copy link

sakhmedbayev commented Oct 9, 2019

here is my temporary solution, switching to ApolloProvider and setting it up to use the link from AppSync

import { Auth } from "aws-amplify"
import { createAppSyncLink } from "aws-appsync"
import awsconfig from './aws-exports'
import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';

const httpLink = createHttpLink({
  uri: awsconfig.aws_appsync_graphqlEndpoint,
});

const awsLink = createAppSyncLink({
  url: awsconfig.aws_appsync_graphqlEndpoint,
  region: awsconfig.aws_appsync_region,
  auth: {
    type: awsconfig.aws_appsync_authenticationType,
    credentials: () => Auth.currentCredentials(),
    jwtToken: async () =>
      (await Auth.currentSession()).getAccessToken().getJwtToken()
  },
  complexObjectsCredentials: () => Auth.currentCredentials()
 })

export default new ApolloClient({
  link: awsLink.concat(httpLink),
  cache: new InMemoryCache()
});

@nc9, is this solution supports AppSync's offline and subscription capabilities?

@undefobj
Copy link
Contributor

undefobj commented Oct 11, 2019

Hello everyone - I want to reply and assure you that we have not abandoned support of this project. Per my earlier comment, this is a complex process and to be completely transparent there are things in the Apollo library that are out of our control and there have also been breaking changes in Apollo versions which we're trying to account for, which is also why we pinned the version. We've been spending many hours trying to account for this but it's not simple to solve. After putting more thought into this we've got some initial solutions that I hope will unblock many of you. What we've done is packaged two of the "Links" which are part of the SDK - the Auth and Subscription Links - and published them to NPM. This will allow you to include them in the newer Apollo versions if you wish to use the newer features. This does not include the "Offline Link" for offline support which is more complex to solve and we're looking into for the future.

Installation of the links:

npm install aws-appsync-auth-link aws-appsync-subscription-link

Usage:
https://github.com/awslabs/aws-mobile-appsync-sdk-js#using-authorization-and-subscription-links-with-apollo-client-no-offline-support

With is I would then give the following recommendations for choosing your client strategy:

  1. If you do not have offline use cases, you can either use the Auth & Subscription Links above with the latest Apollo client or alternatively use the Amplify GraphQL client instead of Apollo:https://aws-amplify.github.io/docs/js/api#amplify-graphql-client
  2. If you do have offline use cases please use the current version as-is with the older Apollo version. We're still working on a future strategy for the Offline Link.

Please let us know if you have any trouble using these links or if there is a scenario which we haven't accounted for here.

@nagad814
Copy link

2. If you do have offline use cases please use the current version as-is with the older Apollo version. We're still working on a future strategy for the Offline Link.

Please give an ETA for this.

@anarerdene
Copy link

Any Update ?

@undefobj
Copy link
Contributor

@nagad814 @anarerdene there is no ETA for an offline link as described above. As I outlined we are evaluating possibilities for the future.

@doldyn
Copy link

doldyn commented Nov 1, 2019

@tgjorgoski, I am sorry for not replying earlier. I can confirm that we use a rewritten version of the AppSync client with Apollo 3 offline using the approach described above. We have converted to use the Apollo hooks pattern and it works well in our use case. We have not changed the local state management. I assume @undefobj has referred to when saying that they need full context of the state in the middleware. This compromise works for us at the moment as we use Redux for our AppState. We use the local state management in Apollo for metadata on mutations and it works fine with the current approach. I look forward to see where AWS is heading with this. We are unfortunately very far from the standard code in a fair few areas making a pull request difficult and maybe not a good idea if AWS is working on a solution. @undefobj, I would be happy to collaborate and contribute if you want someone to work with you on these issues.

@isocra
Copy link

isocra commented Nov 1, 2019

@undefobj, I need the offline capability as I'm building a mobile app. Can you confirm which versions of this SDK, Apollo and any others I can safely use that will work well together?

Thanks

@undefobj
Copy link
Contributor

undefobj commented Nov 1, 2019

@isocra if you require offline per the comments above and the documentation you can use 2.4.6 with the standard client and don't need a link.

@isocra
Copy link

isocra commented Nov 4, 2019

Hi again @undefobj,

Here's what I've got currently (plus a bunch of non-relevant other packags), which would you recommend I upgrade/downgrade (I can't see which should be 2.4.6)?

    "apollo-client": "^2.5.1",
    "aws-amplify": "^1.1.27",
    "aws-amplify-react-native": "^2.1.11",
    "aws-appsync": "^1.7.2",
    "aws-appsync-react": "^1.2.7",
    "expo": "^33.0.0",
    "graphql": "^14.3.0",
    "graphql-tag": "^2.10.1",
    "react": "16.8.3",
    "react-apollo": "^2.5.8",
    "react-native": "https://github.com/expo/react-native/archive/sdk-33.0.0.tar.gz",

Thanks!

@VicFrolov
Copy link

VicFrolov commented Dec 6, 2019

Hello,

I got this working, but unfortunately for logged out users (using cognito pools), queries [that used to work] are perpetually stuck on 'loading', with no data for 'data' or 'error'. I have tried to rerun amplify auth update, and ensured that I selected unauthed users to have access: Allow unauthenticated logins? (Provides scoped down permissions that you can control via AWS IAM) Yes.

In the console:

"Possible Unhandled Promise Rejection (id: 1):
"No current user"

Auth.currentCredentials returns what appears to be a valid CognitoIdentityCredentials, currentSession throws an error saying no current user.

I followed @undefobj writeup.

const url = awsconfig.aws_appsync_graphqlEndpoint;
const region = awsconfig.aws_appsync_region;
const auth = {
  jwtToken: async () =>
    (await Auth.currentSession()).getIdToken().getJwtToken(),
  type: awsconfig.aws_appsync_authenticationType,
} as AuthOptions;

const httpLink = createHttpLink({ uri: url });
const link = ApolloLink.from([
  createAuthLink({ auth, region, url }),
  createSubscriptionHandshakeLink(url, httpLink),
]);

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

Any suggestions?

@isocra
Copy link

isocra commented Jan 8, 2020

Hi @undefobj,

Is there any sort of roadmap for fixes to this?

I've just spent several days trying to upgrade to Expo36 (which includes RN0.61 and React 16.9), but I'm ready to give up as I can't get it working :-(

Our constraint is that we need the offline capability for our app plus we need the very neat AppSync feature that allows us to upload images, so, as per your comment above, we're stuck with using apollo-client@2.4.6. But this isn't compatible with React 16.9 as it uses componentWillReceiveProps, so we get warnings when we start up the app.

In fact in order to make it work (and to fix an issue where you have pending mutations that include images as Blobs), we've had to create our own versions of AWSAppSyncClient and the store and offline-link. We've actually got everything working with Expo locally, just with warnings about the lifecycle methods and RNCNetInfo. But when I build an APK and try that it crashes on startup with an error saying Expo encountered a fatal error: RNCNetInfo.getCurrentState got 3 arguments, expected 2. We're not using RNCNetInfo at all, but it's used in Rehydrate, so we've created our own version of that, and we still get the error.

We seem to be completely stuck! As far as I can tell, it's just NOT possible to use AWS AppSync with offline and image upload capability with RN0.61 and React 16.9.

In case it's useful to anyone, here is the set of packages that we've managed to get working together.

    "@react-native-community/async-storage": "^1.7.1",
    "@react-native-community/netinfo": "4.6.0",
    "@redux-offline/redux-offline": "2.5.2-native.0",
    "apollo-cache-inmemory": "^1.6.5",
    "apollo-client": "2.4.6",
    "apollo-link-http": "^1.5.16",
    "aws-amplify": "2.2.1",
    "aws-amplify-react-native": "^2.1.11",
    "aws-appsync": "3.0.2",
    "aws-appsync-auth-link": "^2.0.1",
    "aws-appsync-react": "3.0.2",
    "aws-appsync-subscription-link": "^2.0.1",

@SebSchwartz
Copy link

@undefobj @dabit3 @elorzafe @manueliglesias Any news for this issue? Should we switch to Amplify Datastore (as it is low low low priority in the backlog) or it's still going to be resolved?

@mikedizon
Copy link

mikedizon commented Feb 14, 2020

Hello everyone - I want to reply and assure you that we have not abandoned support of this project. Per my earlier comment, this is a complex process and to be completely transparent there are things in the Apollo library that are out of our control and there have also been breaking changes in Apollo versions which we're trying to account for, which is also why we pinned the version. We've been spending many hours trying to account for this but it's not simple to solve. After putting more thought into this we've got some initial solutions that I hope will unblock many of you. What we've done is packaged two of the "Links" which are part of the SDK - the Auth and Subscription Links - and published them to NPM. This will allow you to include them in the newer Apollo versions if you wish to use the newer features. This does not include the "Offline Link" for offline support which is more complex to solve and we're looking into for the future.

Installation of the links:

npm install aws-appsync-auth-link aws-appsync-subscription-link

Usage:
https://github.com/awslabs/aws-mobile-appsync-sdk-js#using-authorization-and-subscription-links-with-apollo-client-no-offline-support

With is I would then give the following recommendations for choosing your client strategy:

  1. If you do not have offline use cases, you can either use the Auth & Subscription Links above with the latest Apollo client or alternatively use the Amplify GraphQL client instead of Apollo:https://aws-amplify.github.io/docs/js/api#amplify-graphql-client
  2. If you do have offline use cases please use the current version as-is with the older Apollo version. We're still working on a future strategy for the Offline Link.

Please let us know if you have any trouble using these links or if there is a scenario which we haven't accounted for here.

@undefobj Have you guys confirmed that this works with cognito user pools?

Here's how I am setting up my client.

const config = {
  url: awsconfig.aws_appsync_graphqlEndpoint,
  region: awsconfig.aws_appsync_region,
  auth: {
    type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS,
    jwtToken: async () =>
      (await Auth.currentSession()).getIdToken().getJwtToken(),
  },
  disableOffline: true,
};

const link = ApolloLink.from([
  createAppSyncLink(config),
  createAuthLink(config),
  createSubscriptionHandshakeLink(config),
]);

export const client = new ApolloClient({
  link,
  cache: new InMemoryCache({addTypename: false}),
});

My packages.json:

  "dependencies": {
    "@apollo/client": "^3.0.0-beta.32",
    "@apollo/link-ws": "^2.0.0-beta.3",
    "apollo-link": "^1.2.13",
    "apollo-link-ws": "^1.0.19",
    "apollo-utilities": "^1.3.3",
    "react-native": "0.61.5",
    "subscriptions-transport-ws": "^0.9.16",
     "amazon-cognito-identity-js": "^3.2.4"
  },

The connection seems to be successful, but nothing happens for the event that I'm subscribing to (onUpdateLocation) in my case.

Here is an example of what appears to be a successful connection (passing owner).

Screen Shot 2020-02-14 at 4 07 57 PM

Here is an example of an intentional bad connection (not passing owner).

Screen Shot 2020-02-14 at 4 04 07 PM

@wolfeidau
Copy link

I put together an example application of my own https://github.com/wolfeidau/appsync-apollo-links which demonstrates realtime websocket connections.

Screenshot from 2020-02-15 12-56-28

@mikedizon
Copy link

mikedizon commented Feb 15, 2020

@wolfeidau thanks for this. looks like we are doing the same thing with the exception of authentication modes.

edit: I added an additional subscription type updateLocation. i can see the updated data getting pushed out, but it looks like it allows anyone to see data that gets updated, which definitely does not work for our use case.

@dabit3 @manueliglesias is this a bug?

@darrenfurr
Copy link

@mikedizon - did you ever get this working with @apollo/react-hooks & Cognito User Pools? I'm getting a 401 when I try @wolfeidau example.

@mikedizon
Copy link

mikedizon commented Feb 17, 2020

@darrenfurr with user pools I did not. @wolfeidau's example works, but the custom subscription he's using is public

edit: thanks for confirming the same behavior. don't want to spend more time chasing ghosts, or questioning my implementation.

@wolfeidau
Copy link

I am working on adding Cognito pool authentication to the example as it is the more common requirement.

I am planning to add this using @amplify/auth and react-amplify.

Hopefully that will round it out as a more generally usable sample as well!

@mikedizon
Copy link

@wolfeidau hopefully that works with Apollo Client. Having to refactor the entire project isn’t an option. I based my design under the assumption that Apollo client was the way to go given the example provided by the contributors.

@wolfeidau
Copy link

My example at https://github.com/wolfeidau/appsync-apollo-links is now includes support for Cognito Pools rather than just API key.

Everything is working 👍 which is great!

@mikedizon
Copy link

@wolfeidau oh my god. the only thing I was missing was Auth.configure(awsconfig);

@wolfeidau
Copy link

This was the aim of my complete example, over fragments.

Great to hear it has helped!

@darrenfurr
Copy link

For what it's worth these packages worked for me. I'm using the apollo hooks library primarily.

"dependencies": {
    "@apollo/react-hooks": "^3.1.3",
    "apollo-cache-inmemory": "^1.6.5",
    "apollo-client": "2.6.8",
    "apollo-link": "^1.2.13",
    "apollo-link-ws": "^1.0.19",
    "aws-appsync-auth-link": "^2.0.1",
    "aws-appsync-subscription-link": "^2.0.1",
    "graphql-tag": "^2.10.3",
}

Implementation:

const config = {
    url: window.env.REACT_APP_AWS_APPSYNC_GRAPHQL_ENDPOINT,
    region: window.env.REACT_APP_AWS_REGION,
    auth: {
      type: 'AMAZON_COGNITO_USER_POOLS',
      jwtToken: jwtToken,
    },
    disableOffline: true,
  };

  const cache = new InMemoryCache({ addTypename: false }); //apollo-client/issues/1564

  const link = ApolloLink.from([createAuthLink(config), createSubscriptionHandshakeLink(config)]);

  return new ApolloClient({
    link,
    cache,
  });

@JuanmaMenendez
Copy link

JuanmaMenendez commented Feb 22, 2020

@darrenfurr Don't you need to use <Rehydrated> for nothing ?

@darrenfurr
Copy link

@JuanmaMenendez - I'm not sure what you're asking.

@JuanmaMenendez
Copy link

*<Rehydrated> @darrenfurr

@darrenfurr
Copy link

I'm not using Rehydrated because we're disableOffline: true

@elorzafe elorzafe added appsync-core Related to core updates within AppSync SDK React Issues in regards to React and AppSync SDK to-be-reproduced We need to reproduce this issue Apollo labels Apr 15, 2020
@willsamu
Copy link

Hello everyone, I have just published an article on how to set up AWS AppSync with react apollo 3.x, react hooks and offline support. Hope it helps!

@Somtozech
Copy link

@wolfeidau can you confirm your solution works with complex objects (ie single mutation that adds records to dynamo DB and uploads the file to s3)?

@nagad814
Copy link

nagad814 commented Aug 5, 2020

happy anniversary, thanks to bugs like these I have moved / actively don't recommend Appsync

@mikeRChambers610
Copy link

mikeRChambers610 commented Aug 26, 2020

@willsamu it turns out that this does not fix the issue in my case since I am not using useMutation or useQuery.

I am using import {compose, graphql } from 'react-apollo';

UPDATE
I got this working in my app by upgrading react-apollo to ^3.1.5. Then I needed to replace the react-apollo compose with the lodash compose below:

import {flowRight as compose} from 'lodash';

@snowjujube
Copy link

Hello everyone - I want to reply and assure you that we have not abandoned support of this project. Per my earlier comment, this is a complex process and to be completely transparent there are things in the Apollo library that are out of our control and there have also been breaking changes in Apollo versions which we're trying to account for, which is also why we pinned the version. We've been spending many hours trying to account for this but it's not simple to solve. After putting more thought into this we've got some initial solutions that I hope will unblock many of you. What we've done is packaged two of the "Links" which are part of the SDK - the Auth and Subscription Links - and published them to NPM. This will allow you to include them in the newer Apollo versions if you wish to use the newer features. This does not include the "Offline Link" for offline support which is more complex to solve and we're looking into for the future.

Installation of the links:

npm install aws-appsync-auth-link aws-appsync-subscription-link

Usage:
https://github.com/awslabs/aws-mobile-appsync-sdk-js#using-authorization-and-subscription-links-with-apollo-client-no-offline-support

With is I would then give the following recommendations for choosing your client strategy:

  1. If you do not have offline use cases, you can either use the Auth & Subscription Links above with the latest Apollo client or alternatively use the Amplify GraphQL client instead of Apollo:https://aws-amplify.github.io/docs/js/api#amplify-graphql-client
  2. If you do have offline use cases please use the current version as-is with the older Apollo version. We're still working on a future strategy for the Offline Link.

Please let us know if you have any trouble using these links or if there is a scenario which we haven't accounted for here.

nice solution!!! thank you bro!!!!!!

@m-yousri
Copy link

here is my temporary solution, switching to ApolloProvider and setting it up to use the link from AppSync

import { Auth } from "aws-amplify"
import { createAppSyncLink } from "aws-appsync"
import awsconfig from './aws-exports'
import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';

const httpLink = createHttpLink({
  uri: awsconfig.aws_appsync_graphqlEndpoint,
});

const awsLink = createAppSyncLink({
  url: awsconfig.aws_appsync_graphqlEndpoint,
  region: awsconfig.aws_appsync_region,
  auth: {
    type: awsconfig.aws_appsync_authenticationType,
    credentials: () => Auth.currentCredentials(),
    jwtToken: async () =>
      (await Auth.currentSession()).getAccessToken().getJwtToken()
  },
  complexObjectsCredentials: () => Auth.currentCredentials()
 })

export default new ApolloClient({
  link: awsLink.concat(httpLink),
  cache: new InMemoryCache()
});

I tried this but ApolloClient Doesn't support MQTT protocol so AWS app sync subscriptions are not working

@muninderkaur06
Copy link

here is my temporary solution, switching to ApolloProvider and setting it up to use the link from AppSync

import { Auth } from "aws-amplify"
import { createAppSyncLink } from "aws-appsync"
import awsconfig from './aws-exports'
import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';

const httpLink = createHttpLink({
  uri: awsconfig.aws_appsync_graphqlEndpoint,
});

const awsLink = createAppSyncLink({
  url: awsconfig.aws_appsync_graphqlEndpoint,
  region: awsconfig.aws_appsync_region,
  auth: {
    type: awsconfig.aws_appsync_authenticationType,
    credentials: () => Auth.currentCredentials(),
    jwtToken: async () =>
      (await Auth.currentSession()).getAccessToken().getJwtToken()
  },
  complexObjectsCredentials: () => Auth.currentCredentials()
 })

export default new ApolloClient({
  link: awsLink.concat(httpLink),
  cache: new InMemoryCache()
});

I've used the same code in the project but this doesn't seem to work in production. Any configuration that I should follow? Please help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Apollo appsync-core Related to core updates within AppSync SDK React Issues in regards to React and AppSync SDK to-be-reproduced We need to reproduce this issue
Projects
None yet
Development

No branches or pull requests