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":
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):
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:
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:
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://dev.to/sayanide/beginner-s-guide-to-using-websockets-in-apollo-client-graphql-subscription-11m
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:
Comments