Subscribe only available for AWS AppSync endpoint - reactjs

I get issues when using #apollo/client: 3.5.10, aws-appsync:4.1.5.
There is my config
import { ApolloClient, ApolloLink, createHttpLink, InMemoryCache } from '#apollo/client';
import { createAuthLink } from 'aws-appsync-auth-link';
import { createSubscriptionHandshakeLink } from 'aws-appsync-subscription-link';
// Config
import { AWS_APPSYNC } from '../config';
const { graphqlEndpoint, region, apiKey } = AWS_APPSYNC;
const auth = {
type: AWS_APPSYNC.authenticationType,
apiKey: apiKey,
};
const httpLink = createHttpLink({ uri: graphqlEndpoint });
const link = ApolloLink.from([
// #ts-ignore
createAuthLink({ graphqlEndpoint, region, auth }),
// #ts-ignore
createSubscriptionHandshakeLink({ graphqlEndpoint, region, auth }, httpLink),
]);
export const client = new ApolloClient({
link,
cache: new InMemoryCache(),
});
and I am using
const {
data: subscription_message_data,
loading: subscription_message_loading,
error: subscription_message_error
} = useSubscription(
SUBSCRIPTION_NEW_MESSAGE, {
variables: { conversationId: conversationId }
});
But I got an error form useSubscription is: "Subscribe only available for AWS AppSync endpoint"
Does anyone have experience with this issue?

Had the exact same issue, and was baffled by this error message.
At the end the issue turned out to be the incorrect property name for the url used in the createAuthLink and createSubscriptionHandshakeLink input objects.
This was the fix that worked for me:
const link = ApolloLink.from([
createAuthLink({ url: graphQLEndpoint, region, auth }),
createSubscriptionHandshakeLink({ url: graphQLEndpoint, region, auth }, httpLink),
]);

Related

Document is undefined when using apollo query with next.js getServerSideProps

I am trying to use getServerSideProps to fetch a query every time this component is rendered using apollo and next.js
export async function getServerSideProps(context) {
const { data } = await client.query({
query: GET_AUTHED_USER
})
return {
props: { user: data.getAuthedUser },
}
}
const Profile = ({ user }) => {
const router = useRouter();
// const [state, setState] = useState(JSON.parse(router.query.currentUser));
const [state, setState] = useState(user);
console.log(state)
...
APOLLO CONFIG
import { ApolloClient, InMemoryCache, ApolloLink } from '#apollo/client';
import { getCookie } from './utils/functions';
import { setContext } from '#apollo/client/link/context';
import { createUploadLink } from 'apollo-upload-client';
const authLink = setContext((_, { headers }) => {
// get the authentication token from storage if it exists
const token = getCookie('JWT');
// return the headers to the context so httpLink can read them
return {
headers: {
...headers,
authorization: token ? token : '',
}
}
});
const httpLink = createUploadLink({
uri: 'http://localhost:5000/graphql',
});
const client = new ApolloClient({
uri: 'http://localhost:5000/graphql',
cache: new InMemoryCache(),
link: ApolloLink.from([authLink, httpLink])
});
export default client;
currently, when visiting the /profile page I receive the error:
Server Error
Error: document is not defined
Does anyone have any insight on how to resolve this or suggest a valid work around?
appolo/client is a client side library. getServersideProps execute in server side. document doesn't exist in server side. It will only work within client side.
Workaround 1:
You can use swr. swr is for client side data fetch. so you don't need getServerSideProps.
Workaround 2:
You can use apollo-server. Then you can call apollo-server function in getServerSideProps as apollo-server is for server side calling.

How to access the request context from the setContext function from graphql apollo-client in SSR from nextJS?

So I'm trying to do a custom header for the requests to my graphql backend from my nextJS frontend. The code of the graphql client is as follows:
import { ApolloClient, ApolloLink, InMemoryCache, createHttpLink } from '#apollo/client'
import { setContext } from '#apollo/client/link/context'
import getConfig from 'next/config'
import nookies, { parseCookies } from 'nookies'
const { publicRuntimeConfig } = getConfig()
const httpLink = createHttpLink({
uri: publicRuntimeConfig.uri,
credentials: 'same-origin'
})
const authLink = setContext((_, { headers }) => {
let token = ''
if (typeof window !== 'undefined') {
const { 'toDo-token': newToken } = parseCookies()
token = newToken
} else {
// error is right here. I cant find a way to access the ctx
const { 'toDo-token': newToken } = nookies.get(ctx)
token = newToken
}
return {
headers: {
...headers,
Authorization: token ?? undefined
}
}
})
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
ssrMode: typeof window === 'undefined'
})
export default client
On the client side it works just fine. However, since I cant access client cookies on the server side, I'm trying to use the get function from nookies to grab the auth cookies and pass to the headers with the setContext function. The problem I'm having is that I cant find a way to grab the app context from next so I can look at the request info and grab the ctx from there so I can see the cookies.
I do something similar in my _app.tsx in the following way:
MyApp.getInitialProps = async ({ ctx }: AppContext) => {
const { locale } = ctx
const { 'toDo-token': token } = nookies.get(ctx)
let user = null
try {
user = await useUser()
} catch {
user = null
}
return {
locale: locale === 'default' ? 'en' : locale as LocaleEnum,
token: token ?? null,
user
}
}
Does anyone know how I can access the request context in the graphql setContext function?

ApolloProvider with Hot Chocolate API returns 404 for Apollo Client

First time using Hot Chocolate and Apollo and I have an issue where the Apollo client created always returns 404 for the Hot Chocolate API. This API is running on localhost and can be queried fine.
Whats weird is, if I use the Apollo Client getServerSideProps, the query returns fine.
EG This is working
export async function getServerSideProps() {
const { data } = await client.query({
query: gql`
query {
rolesQuery {
roles {
id
name
}
}
}
`,
});
return {
props: { roles: data.rolesQuery.roles, },
};
}
This does not
export function createApolloClient() {
const httpLink = createHttpLink({
uri: process.env.NEXT_PUBLIC_GRAPHQL_API,
fetchOptions: {
mode: 'no-cors',
},
});
const client = new ApolloClient({
link: httpLink,
cache: new InMemoryCache(),
});
return client;
}
// Usage of the client
const apolloClient = createApolloClient();
<ApolloProvider client={apolloClient}>...</ApolloProvider>
At first I had a CORS issue which is fixed but I'm still getting a 404 when calling this from a hook inside a component (using graphql-codegen version 2.6.1).
Any ideas?
Edit
Front end component calling mutation
import React from "react";
import { gql, useMutation } from '#apollo/client';
const REGISTER = gql`
mutation RegisterUser ($email: String!, $password: String!) {
usersMutation {
registerUser (request: { email: $email, password: $password}) {
id
firstName
email
}
}
}
`;
const SignUp = () => {
const [registerUser, { data, loading, error }] = useMutation(REGISTER);
console.log(registerUser())
return <div>code removed for brevity </div>;
};
export default SignUp;

React in heroku does not recognize the environment

I am creating an application in react with graphql for the API and rails as the backend. I have just configured the environment variables so that depending on whether the application is running in production or in development the url that is consumed in the front changes.
But when I deploy in heroku and check the console in the browser, the url of the api is still the development one http://localhost:3000. I don't know why React is not recognizing the production environment in heroku.
I just created a file constant.js:
const prod = {
url: {
API_URL: 'https://hackathon-one-api.herokuapp.com/graphql'
}
}
const dev = {
url: {
API_URL: 'http://localhost:3000/graphql'
}
}
console.log(process.env.NODE_ENV)
export const config = process.env.NODE_ENV === 'development' ? dev : prod;
And in my index.js (where is imported):
// Environments variables
import { config } from '../src/constant';
// 1
import { ApolloProvider } from 'react-apollo';
import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { setContext } from 'apollo-link-context';
import { InMemoryCache } from 'apollo-cache-inmemory';
// 2
const httpLink = createHttpLink({
uri: config.url.API_URL //here!
});
// 3
const authLink = setContext((_, { headers }) => {
// get the authentication token from local storage if it exists
const token = localStorage.getItem('token');
// return the headers to the context so httpLink can read them
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : "",
}
}
});
// 4
export const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache()
})

How can I setup an Apollo client in React for both upload and subscriptions?

I would like to set up a graphql client with React for both uploading file and handle subscriptions from a graphql server.
The file upload and the other queries work well. The problem is with subscriptions. I get in the browser console the following error:
WebSocket connection to 'ws://localhost:3001/subscriptions' failed: Connection closed before receiving a handshake response
I have used apollo-upload-client for file upload and apollo-link-ws for subscriptions.
I can see that subscriptions-transport-ws suggests using createNetworkInterface and addGraphQLSubscriptions but this approach is not compatible with apollo-upload-client that only supports createUploadLink.
I'm stuck. Please help.
I setup my client like this:
import React from 'react';
import ApolloClient from 'apollo-client';
import { ApolloProvider } from 'react-apollo';
import { createUploadLink } from 'apollo-upload-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { ApolloLink, Observable, split } from 'apollo-link';
import { WebSocketLink } from 'apollo-link-ws';
import { getMainDefinition } from 'apollo-utilities';
const cache = new InMemoryCache();
const request = async (operation) => {
const token = localStorage.getItem('token');
operation.setContext({
headers: {
authorization: token ? `Bearer ${token}` : '',
},
});
};
const httpLink = createUploadLink({ uri: 'http://localhost:3001/graphql' });
// Create a WebSocket link:
const wsLink = new WebSocketLink({
uri: 'ws://localhost:3001/subscriptions',
options: {
reconnect: true
},
});
// using the ability to split links, you can send data to each link
// depending on what kind of operation is being sent
const link = split(
// split based on operation type
({ query }) => {
const { kind, operation } = getMainDefinition(query);
return kind === 'OperationDefinition' && operation === 'subscription';
},
wsLink,
httpLink,
);
const requestLink = new ApolloLink((operation, forward) =>
new Observable((observer) => {
let handle;
Promise.resolve(operation)
.then(oper => request(oper))
.then(() => {
handle = forward(operation).subscribe({
next: observer.next.bind(observer),
error: observer.error.bind(observer),
complete: observer.complete.bind(observer),
});
})
.catch(observer.error.bind(observer));
return () => {
if (handle) handle.unsubscribe();
};
}));
const apolloClient = new ApolloClient({
link: ApolloLink.from([
requestLink,
link,
]),
cache,
});
export const withApolloClient = App => (
<ApolloProvider client={apolloClient}>
<App client={apolloClient} />
</ApolloProvider>
);
export default apolloClient;
I am using a similar config but instead of importing WebSocketLink from apollo-link-ws I imported it from #apollo/client.
With that setup i had both the subscription and upload working.
import { WebSocketLink } from "#apollo/client/link/ws";
I would suggest to use graphql-server-express like this

Resources