Getting Apollo client to work with @aws_subscribe
Tags: appsync, graphql, apolloclient
Published: 2021-12-13 00:43:13

---
title: Getting Apollo client to work with @aws_subscribe
published: true
description: This post describes how to get Apollo client to work for AWS AppSync queries, mutations, and subscriptions
tags: AppSync, GraphQL, ApolloClient
//cover_image: https://direct_url_to_image.jpg
---

I'm building my killer mobile app on graphql. 

On the backend I'm using AWS AppSync -- I'm still not bought into the magic of Amplify -- there is just a way too much magic going on behind the scenes, which might work for simple HelloWorld projects, but, if I'm going to scale my app eventually (and I am going to), I'd better really understand what's going on. 


Apollo is the de-factor standard for GraphQL client. Unfortunately, Apollo is progressing forward little faster than AWS AppSync. As such, Apollo's latest version does not support headers passing for web sockets connection (like it used to in the earlier versions). This means that getting it to work with AppSync subscriptions is going to be a challenge.


I spent fair amount of time reading all the blogs and stack overflow questions for the past 2 years -- non of them worked for me. The simplest solution that I was able to come up with -- use the latests Apollo client for "queries" and "mutations", but fall back for the AWS client  implementation for "subscriptions".


Here is the JS file that defines a connection which can be used for "queries" and "mutations": 

```JavaScript
import { setContext } from '@apollo/client/link/context'

import {
  ApolloClient,
  InMemoryCache,
  HttpLink,
} from "@apollo/client"

import { API_URI, API_KEY } from "@env"

const authLink = setContext((_, { headers }) => {
  return {
    headers: {
      ...headers,
      'X-Api-Key': API_KEY,
    },
  }
})
const httpLink = new HttpLink({
  uri: API_URI,
})

export const gqlClient = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache(),
})
```

I do define a different type of the gql connection to be used with "subscriptions" in the following js file (note, that the end point URL is exactly the same as for the other connection, which is different in most of the docs I was reading):

```JavaScript
import { createAuthLink } from "aws-appsync-auth-link"
import { createSubscriptionHandshakeLink } from "aws-appsync-subscription-link"

import { ApolloLink } from "apollo-link"
import { createHttpLink } from "apollo-link-http"
import ApolloClient from "apollo-client"
import { InMemoryCache } from "apollo-cache-inmemory"

import {
  API_URI, API_KEY, REGION,
} from "@env"

const url = API_URI
const region = REGION
const auth = {
  type: 'API_KEY',
  apiKey: API_KEY,
}

const httpLink = createHttpLink({ uri: url })

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

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

export default subscriptionClient
```

Here is how I call gql query:

```JavaScript
import * as CONST from '../../consts.js'

const messagesList = (await CONST.gqlClient
        .query({
          query: gql`
        query getMessagesList($chatUuid: String!, $lastLoaded: AWSDateTime!) {
          getMessagesList(chatUuid: $chatUuid, lastLoaded: $lastLoaded){
            uuid,
            messageUuid, 
            text, 
            createdAt,
            updatedAt
          }
        }`,
          variables: {
            chatUuid,
            lastLoaded,
          },
          // fetchPolicy: "network-only",
        })).data.getMessagesList
      
```


And the subscription is called like this:

```JavaScript
import subscriptionClient from '../../subscriptionClient'

const subscription = subscriptionClient
      .subscribe({
        query: gql`
        subscription onSendMessage($chatUuid: String!) {
          onSendMessage (chatUuid: $chatUuid) {
            chatUuid
            createdAt
            messageUuid
            text
            updatedAt
            uuid          }
        }
        `,
        variables: {
          chatUuid,
        },
      })
      .subscribe({
        next(data) {
          console.log({ data })
        },
        error({ error }) {
          console.log({ error })
        },
        complete() { console.log("subs. DONE") }, // never printed
      })

```

Unfortunately, I have to import 2 sets of Apollo npm's -- one from Apollo and the other one from AWS AppSynch. Hopefully this will not cause conflict in the nearest future, and hopefully AWS will fgure how how to make AppSync to work not only with Amplify, but also with more standard solutions like Apollo client.


To come up with this simple solution I had to sift through the following list of blog posts:

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

https://www.tutorialguruji.com/react-js/appsync-subscriptions-with-apolloclient-in-react 

https://dev.to/sayanide/beginner-s-guide-to-using-websockets-in-apollo-client-graphql-subscription-11m

https://github.com/apollographql/apollo-feature-requests/issues/224

 

I posted the original questions here: https://stackoverflow.com/questions/70326194/authenticating-apollo-client-for-appsync-to-work-with-aws-subscribe 

and glad that I was able to provide a solution for it.


If you are interested, here are the links to my mobile killer app:


https://github.com/echowaves/WiSaw 

https://github.com/echowaves/WiSaw.cdk 

https://www.wisaw.com/ 

And this was originally posted here: https://www.echowaves.com/post/getting-apollo-client-to-work-with-aws_subscribe