import { ApolloClient } from 'apollo-client' import { InMemoryCache } from 'apollo-cache-inmemory' import { HttpLink } from 'apollo-link-http' import { WebSocketLink } from 'apollo-link-ws' import { onError } from 'apollo-link-error' import { setContext } from 'apollo-link-context' import { ApolloLink, split } from 'apollo-link' import { getMainDefinition } from 'apollo-utilities' import { MessageState } from './components/messages/Messages' import urlJoin from 'url-join' const GRAPHQL_ENDPOINT = process.env.API_ENDPOINT ? urlJoin(process.env.API_ENDPOINT, '/graphql') : urlJoin(location.origin, '/api/graphql') const httpLink = new HttpLink({ uri: GRAPHQL_ENDPOINT, credentials: 'same-origin', }) console.log('GRAPHQL ENDPOINT', GRAPHQL_ENDPOINT) const apiProtocol = new URL(GRAPHQL_ENDPOINT).protocol let websocketUri = new URL(GRAPHQL_ENDPOINT) websocketUri.protocol = apiProtocol === 'https:' ? 'wss:' : 'ws:' const wsLink = new WebSocketLink({ uri: websocketUri, credentials: 'same-origin', options: { reconnect: true, connectionParams: { Authorization: `Bearer ${localStorage.getItem('token')}`, }, }, }) const link = split( // split based on operation type ({ query }) => { const definition = getMainDefinition(query) return ( definition.kind === 'OperationDefinition' && definition.operation === 'subscription' ) }, wsLink, httpLink ) const linkError = onError(({ graphQLErrors, networkError }) => { let errorMessages = [] if (graphQLErrors) { graphQLErrors.map(({ message, locations, path }) => console.log( `[GraphQL error]: Message: ${message}, Location: ${JSON.stringify( locations )} Path: ${path}` ) ) if (graphQLErrors.length == 1) { errorMessages.push({ header: 'Something went wrong', content: `Server error: ${graphQLErrors[0].message} at (${graphQLErrors[0].path})`, }) } else if (graphQLErrors.length > 1) { errorMessages.push({ header: 'Multiple things went wrong', content: `Received ${graphQLErrors.length} errors from the server. See the console for more information`, }) } } if (networkError) { console.log(`[Network error]: ${JSON.stringify(networkError)}`) localStorage.removeItem('token') const errors = networkError.result.errors if (errors.length == 1) { errorMessages.push({ header: 'Server error', content: `You are being logged out in an attempt to recover.\n${errors[0].message}`, }) } else if (errors.length > 1) { errorMessages.push({ header: 'Multiple server errors', content: `Received ${graphQLErrors.length} errors from the server. You are being logged out in an attempt to recover.`, }) } } if (errorMessages.length > 0) { const newMessages = errorMessages.map(msg => ({ key: Math.random().toString(26), type: 'message', props: { negative: true, ...msg, }, })) MessageState.set(messages => [...messages, ...newMessages]) } }) 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}` : '', }, } }) const client = new ApolloClient({ link: ApolloLink.from([linkError, authLink.concat(link)]), cache: new InMemoryCache(), }) export default client