12

AppSync uses MQTT over WebSockets for its subscription, yet Apollo uses WebSockets. Neither Subscription component or subscribeForMore in Query component works for me when using apollo with AppSync.

One AppSync feature that generated a lot of buzz is its emphasis on real-time data. Under the hood, AppSync’s real-time feature is powered by GraphQL subscriptions. While Apollo bases its subscriptions on WebSockets via subscriptions-transport-ws, subscriptions in GraphQL are actually flexible enough for you to base them on another messaging technology. Instead of WebSockets, AppSync’s subscriptions use MQTT as the transport layer.

Is there any way to make use of AppSync while still using Apollo?

Sergey V.
  • 840
  • 8
  • 15
C.Lee
  • 10,451
  • 9
  • 31
  • 46

2 Answers2

14

Ok, here is how it worked for me. You'll need to use aws-appsync SDK (https://github.com/awslabs/aws-mobile-appsync-sdk-js) to use Apollo with AppSync. Didn't have to make any other change to make subscription work with AppSync.

Configure ApolloProvider and client:

    // App.js
    import React from 'react';
    import { Platform, StatusBar, StyleSheet, View } from 'react-native';
    import { AppLoading, Asset, Font, Icon } from 'expo';
    import AWSAppSyncClient from 'aws-appsync' // <--------- use this instead of Apollo Client
    import {ApolloProvider} from 'react-apollo' 
    import { Rehydrated } from 'aws-appsync-react' // <--------- Rehydrated is required to work with Apollo

    import config from './aws-exports'
    import { SERVER_ENDPOINT, CHAIN_ID } from 'react-native-dotenv'
    import AppNavigator from './navigation/AppNavigator';

    const client = new AWSAppSyncClient({
      url: config.aws_appsync_graphqlEndpoint,
      region: config.aws_appsync_region,
      auth: {
        type: config.aws_appsync_authenticationType,
        apiKey: config.aws_appsync_apiKey,
        // jwtToken: async () => token, // Required when you use Cognito UserPools OR OpenID Connect. token object is obtained previously
      }
    })


    export default class App extends React.Component {
      render() {
        return <ApolloProvider client={client}>
          <Rehydrated>
            <View style={styles.container}>
              <AppNavigator />
            </View>
          </Rehydrated>  
        </ApolloProvider>
    }

Here is how the subscription in a component looks like:

    <Subscription subscription={gql(onCreateBlog)}>
      {({data, loading})=>{
        return <Text>New Item: {JSON.stringify(data)}</Text>
      }}
    </Subscription>
Arjun Sunil Kumar
  • 1,781
  • 3
  • 28
  • 46
C.Lee
  • 10,451
  • 9
  • 31
  • 46
  • 1
    I just wanted to mention that the `aws-exports` file comes from the main page of AppSync from the JavaScript tabs. Down in the page, there's a button that says "Download config". That's the file you want to include. – Jose A Aug 21 '19 at 04:03
  • In addition, if you're using TypeScript, check this link out: https://github.com/awslabs/aws-mobile-appsync-sdk-js/issues/362 There seems to be a Typings issue from the AppSync Client (outdated typings) – Jose A Aug 21 '19 at 04:18
  • @C.Lee Did you have any problems with broken websockets after network change? Should it re-connect automatically after e.g. VPN connect? – raduy Oct 15 '21 at 09:40
  • With this code, isn't it only working on development machine? How do you get it to work in production? – Dreamer Nov 11 '22 at 15:57
  • As per Jan 1, 2022 MTQQ is no longer available as protocol in AppSync https://docs.aws.amazon.com/appsync/latest/devguide/aws-appsync-real-time-data.html – deerawan Jun 15 '23 at 03:19
4

Just to add a note about the authentication as it took me a while to work this out:

If the authenticationType is "API_KEY" then you have to pass the apiKey as shown in @C.Lee's answer.

  auth: {
    type: config.aws_appsync_authenticationType,
    apiKey: config.aws_appsync_apiKey,
  }

If the authenticationType is "AMAZON_COGNITO_USER_POOLS" then you need the jwkToken, and if you're using Amplify you can do this as

  auth: {
    type: config.aws_appsync_authenticationType,
    jwtToken: async () => {
      const session = await Auth.currentSession();
      return session.getIdToken().getJwtToken();
    }
  }

But if your authenticationType is "AWS_IAM" then you need the following:

  auth: {
    type: AUTH_TYPE.AWS_IAM,
    credentials: () => Auth.currentCredentials()
  }
DenisH
  • 859
  • 8
  • 12
  • Hey Denis, Do you have a solution for AMAZON_COGNITO_USER_POOLS where Amplify is not being used? I cannot find it anywhere, but cant use Amplify on this project – JoshuaJames Jun 02 '21 at 04:09
  • Sorry @JoshuaJames, I don't. We've used Amplify in our React Native app and in the web version we've used the Cognito UI provided by AWS. It's a bit basic but it does the job. – DenisH Jun 02 '21 at 11:04