Proper way to setup AWSAppSyncClient, Apollo & React - graphql

I've been having issues getting started with React, Apollo, and AWS-AppSync. I can't resolve this error message:
TypeError: this.currentObservable.query.getCurrentResult is not a function
I'm using the updated packages of #apollo/react-hooks and aws-appsync.
My current setup looks like this.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import config from './aws-exports';
import AWSAppSyncClient from 'aws-appsync';
import { ApolloProvider } from '#apollo/react-hooks';
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
}
});
ReactDOM.render(
<ApolloProvider client={client}>
<React.StrictMode>
<App />
</React.StrictMode>
</ApolloProvider>,
document.getElementById('root')
);
And I have a function that makes a query that looks like this:
import React from 'react';
import { useQuery } from '#apollo/react-hooks';
import gql from 'graphql-tag';
const Flavors = () => {
const GET_FLAVORS = gql`
query listAll {
items {
name,
image
}
}
`;
const { loading, error, data } = useQuery(GET_FLAVORS);
if(loading) return <p>loading...</p>
if(error) return <p>Something went wrong...</p>
return (
<div>
{
data.listIceCreamTypes.items.map(type => {
return <div key={type.name}>
<img src={type.image} alt={type.name} />
<h1>{type.name}</h1>
</div>
})
}
</div>
)
}
export default Flavors;
I've gone through various solutions described in https://github.com/apollographql/react-apollo/issues/3148 such as adding:
"resolutions": {
"apollo-client": "2.6.3"
}
to package.json. Then re-running npm install and restarting the server.
Nothing seems to solve my issues.
Edit** Here's a repo to reproduce the problem: https://github.com/Rynebenson/IceCreamQL

I already answered this on other related question here on stackoverflow..
As mentioned in other answer the problem is because aws-appsync is relying in an previous version apollo-client. Using resolutions is not the "cleaner" way to solve this problem as you're fixing a dependency version which is not fully compatible with this library.
I strongly recommend you to create a custom apollo client for AWS AppSync this way:
import { ApolloProvider } from '#apollo/react-hooks';
import { ApolloLink } from 'apollo-link';
import { createAuthLink } from 'aws-appsync-auth-link';
import { createHttpLink } from 'apollo-link-http';
import { AppSyncConfig } from './aws-exports';
import ApolloClient from 'apollo-client';
const url = AppSyncConfig.graphqlEndpoint;
const region = AppSyncConfig.region;
const auth = {
type: AppSyncConfig.authenticationType,
apiKey: AppSyncConfig.apiKey
};
const link = ApolloLink.from([
createAuthLink({ url, region, auth }),
createHttpLink({ uri: url })
]);
const client = new ApolloClient({
link,
cache: new InMemoryCache()
});
const WithProvider = () => (
<ApolloProvider client={client}>
<App />
</ApolloProvider>
)
export default WithProvider
I also created a more detailed post on medium

Wanted to post my experience that is a more recent. The accepted answer is still correct. aws-appsync uses outdated packages which conflict with the newest versions of the apollo client.
import React from 'react';
import PropTypes from 'prop-types';
// Apollo Settings
import { ApolloClient, ApolloProvider, InMemoryCache } from '#apollo/client';
import { ApolloLink } from 'apollo-link';
// AppSync
import { Auth } from 'aws-amplify';
import { createAuthLink } from 'aws-appsync-auth-link';
import { createHttpLink } from 'apollo-link-http';
import awsconfig from 'assets/lib/aws-exports';
// jwtToken is used for AWS Cognito.
const client = new ApolloClient({
link: ApolloLink.from([
createAuthLink({
url: awsconfig.aws_appsync_graphqlEndpoint,
region: awsconfig.aws_appsync_region,
auth: {
type: awsconfig.aws_appsync_authenticationType,
apiKey: awsconfig.aws_appsync_apiKey,
jwtToken: async () => (await Auth.currentSession()).getAccessToken().getJwtToken(),
},
}),
createHttpLink({ uri: awsconfig.aws_appsync_graphqlEndpoint }),
]),
cache: new InMemoryCache(),
});
const withApollo = ({ children}) => {
return <ApolloProvider client={client}><App /></ApolloProvider>;
};
withApollo.propTypes = {
children: PropTypes.object,
authData: PropTypes.object,
};
export default withApollo;
Package.json
"#apollo/client": "^3.3.15",
"#apollo/react-hooks": "^4.0.0",
"apollo-link": "^1.2.14",
"apollo-link-http": "^1.5.17",
"aws-amplify": "^3.3.27",
"aws-amplify-react-native": "^4.3.2",
"aws-appsync-auth-link": "^3.0.4",

You must initialize appsync like the following method.
const graphqlClient = new appsync.AWSAppSyncClient({
url: graphqlEndpoint,
region: process.env.AWS_REGION,
auth: {
type: 'AWS_IAM',
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
sessionToken: process.env.AWS_SESSION_TOKEN
}
},
disableOffline: true
});

Related

Nest could not find GraphQLModule element

I'm trying to write the e2e test for my backend app (nestjs, grpahql, mongodb).
This is my test:
import { INestApplication } from '#nestjs/common';
import { GraphQLModule } from '#nestjs/graphql';
import { Test, TestingModule } from '#nestjs/testing';
import {
ApolloServerTestClient,
createTestClient,
} from 'apollo-server-testing';
import gql from 'graphql-tag';
import { UserModule } from '../src/user/user.module';
import { MongooseModule } from '#nestjs/mongoose';
import config from '../src/environments/environment';
describe('User', () => {
let app: INestApplication;
let apolloClient: ApolloServerTestClient;
beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [UserModule, MongooseModule.forRoot(config.mongoURI)],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
const module: GraphQLModule = moduleFixture.get<GraphQLModule>(
GraphQLModule,
);
apolloClient = createTestClient((module as any).apolloServer);
});
it('should get users', async () => {
const { query } = apolloClient;
const result: any = await query({
query: gql`
query {
getUsers {
_id
name
}
}
`,
variables: {},
});
console.log(result);
});
});
I face this error:
Nest could not find GraphQLModule element (this provider does not exist in the current context)
Could someone share a working example or point me what is wrong?
It looks like GraphQLModule is not imported in the scope of your TestModule. If so, the context will never be able to provide it using get().
Also, this might not help you but this is what we do in our projects:
beforeAll(async () => {
const TCP_PORT = 4242;
const testingModule = await Test.createTestingModule({
imports: [AppModule],
}).compile();
gqlClient = new ApolloClient({
uri: `http://localhost:${TCP_PORT}/graphql`,
fetch: fetch as any,
cache: new InMemoryCache({
addTypename: false,
}),
});
app = testingModule.createNestApplication();
await app.listen(TCP_PORT);
});
I did not add all the imports but here are the most relevant:
import ApolloClient, { gql, InMemoryCache } from 'apollo-boost';
import fetch from 'node-fetch';
I assume you know the other ones and/or don't need them

Apollo Subscription with Gatsby Setup

below is my setup of Gatsby SSR with Apollo for those looking for a solution on how to set them up. Hope it helps those looking online for a solution on how to set up Gatsby with Apollo
Credits: [https://github.com/apollographql/subscriptions-transport-ws/issues/333]
I am not sure at the moment if my onError variable is placed correctly. I will look it up
Nonetheless, subscription with gatsby client-side routes is working fine with this setup
client.js // to be imported into ApolloProvider
import ApolloClient from 'apollo-client'
// import * as ws from 'ws'
// import { createHttpLink } from 'apollo-link-http'
import { split } from 'apollo-link'
// import { setContext } from 'apollo-link-context'
import { onError } from 'apollo-link-error'
import { HttpLink } from 'apollo-link-http'
import { WebSocketLink } from 'apollo-link-ws'
// import fetch from 'isomorphic-fetch' // Comment out this line results in an error ...
import 'isomorphic-fetch'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { getMainDefinition } from 'apollo-utilities'
const HTTP_URI = `http://localhost:4000/graphql`
const WS_URI = `ws://localhost:4000/graphql`
const httplink = new HttpLink({
uri: HTTP_URI,
// credentials: 'same-origin',
// fetch,
})
const wsLink = process.browser
? new WebSocketLink({
// if you instantiate in the server, the error will be thrown
uri: WS_URI,
options: {
reconnect: true,
},
})
: null
const errorLink = onError(({ networkError, graphQLErrors }) => {
if (graphQLErrors) {
graphQLErrors.map(({ message, locations, path }) =>
console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
)
)
}
if (networkError) console.log(`[Network error]: ${networkError}`)
})
const link = process.browser
? split(
//only create the split in the browser
// split based on operation type
({ query }) => {
const { kind, operation } = getMainDefinition(query)
return kind === 'OperationDefinition' && operation === 'subscription'
},
wsLink,
httplink,
errorLink
)
: httplink
export const client = new ApolloClient({
link,
cache: new InMemoryCache(),
})
graphql/subscriptions.js
import gql from 'graphql-tag'
const BOOK_ADDED_SUBSCRIPTION = gql`
subscription {
bookAdded {
_id
title
author
}
}
`
export { BOOK_ADDED_SUBSCRIPTION }

How to do graphql and graphql subscriptions with svelte

To do graphql queries and mutations ive had success with both fetch and svelte-apollo (see https://github.com/timhall/svelte-apollo)
I like the fech approach for its simplicity.
Svelte-apollo features subscriptions and I will try to get it to work.
But are there alternatives?
How do you consume graphql subscriptions with svelte?
Heres my solution, using Apollo:
import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { HttpLink } from 'apollo-link-http';
import { WebSocketLink } from 'apollo-link-ws';
import { split } from 'apollo-link';
import { getMainDefinition } from 'apollo-utilities';
const httpLink = new HttpLink({
uri: 'http://localhost:3000/graphql'
});
const wsLink = new WebSocketLink({
uri: `ws://localhost:3000/subscriptions`,
options: {
reconnect: true
}
});
const link = split(
// split based on operation type
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === 'OperationDefinition' &&
definition.operation === 'subscription'
);
},
wsLink,
httpLink,
);
const client = new ApolloClient({
link,
cache: new InMemoryCache()
});
After all that, you have your client set up. Next,
import gql from 'graphql-tag';
client.subscribe({
query: gql`subscription { whatever }`
}).subscribe(result => console.log(result.data);
I'm using urql's svelte bindings. The documentation also shows how to use the bindings with subscriptions.

Cache is not persisted on refresh

I am working on a nextJS with react-apollo and apollo-client. I am using apollo-cache-persist to persist my data. But when I refresh the page, data are lost.
I tried the solution provided here but sadly didn't work.
import React from "react";
import Head from "next/head";
import App, { Container } from "next/app";
import { ApolloClient } from "apollo-client";
import {ApolloProvider} from "react-apollo";
import { InMemoryCache } from "apollo-cache-inmemory";
import { createHttpLink } from "apollo-link-http";
import { withClientState } from "apollo-link-state";
import fetch from "node-fetch";
import { resolvers, defaults } from "../Container/resolvers";
import { ApolloLink } from "apollo-link";
const cache = new InMemoryCache();
const stateLink = withClientState({
cache,
defaults,
resolvers
});
const httpLink = new createHttpLink({
fetch,
uri: "http://localhost:4444/",
headers: {
"Content-Type": "application/json"
}
});
export const client = new ApolloClient({
link: ApolloLink.from([stateLink, httpLink]),
cache
});
export default class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
return {
pageProps: {
// Call page-level getInitialProps
...(Component.getInitialProps
? await Component.getInitialProps(ctx)
: {})
}
};
}
async ComponentWillMount() {
await persistCache({
cache
});
}
render() {
const { Component, pageProps, store } = this.props;
return (
<ApolloProvider client={client}>
<Container>
<Head>
<title>HELLO WORLD</title>
</Head>
<Component {...pageProps} />
</Container>
</ApolloProvider>
);
}
}
I expect the cache to persist but the cache returns nothing on reload.

ApolloBoost was initialized with unsupported options:

I'm trying to disable cache on Apollo, therefore I'm following the documentation apollo-client
, but I cannot success, I get all the time this warning ApolloBoost was initialized with unsupported options: defaultOptions
Does anyone have the same warning ?
import Vue from 'vue'
import ApolloClient from 'apollo-boost'
const defaultOptions = {
watchQuery: {
fetchPolicy: 'network-only',
errorPolicy: 'ignore'
},
query: {
fetchPolicy: 'network-only',
errorPolicy: 'all'
}
}
const client = new ApolloClient({
defaultOptions: defaultOptions,
)};
It looks like it's because you are using Apollo Boost, a wrapper around Apollo Client with slightly different API.
Try changing your import from:
import ApolloClient from "apollo-boost";
to:
import ApolloClient from "apollo-client";
or in v3:
import { ApolloClient } from '#apollo/client';
The "apollo-client" is more low level and harder to use. That's probably why the team created "apollo-boost".
But looking at the source code "apollo-boost" is a good way to understand how to use the low-level "apollo-client". For example:
import ApolloClient from 'apollo-client';
import { FetchResult } from 'apollo-link';
import { HttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
// in v3, the types moved:
// import { ApolloClient } from '#apollo/client';
const apolloClient = new ApolloClient({
link: new HttpLink({
uri: '/graphql',
credentials: 'same-origin',
}),
cache: new InMemoryCache(),
defaultOptions: {
query: {
errorPolicy: 'all',
},
},
});
See also the docs on migration from Apollo Boost to Apollo Client like Intellidroid said.

Resources