Skip to content

Instantly share code, notes, and snippets.

@bbugh
Last active August 11, 2022 07:42
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bbugh/742942596156830c597aaf0ea7a2d800 to your computer and use it in GitHub Desktop.
Save bbugh/742942596156830c597aaf0ea7a2d800 to your computer and use it in GitHub Desktop.
Apollo Action Cable setup
import { ApolloClient } from 'apollo-client'
import { split } from 'apollo-link'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { getMainDefinition } from 'apollo-utilities'
import { createPersistedQueryLink } from 'apollo-link-persisted-queries'
import { setContext } from 'apollo-link-context'
// AC: IMPORT ACTIONCABLE
import ActionCable from 'actioncable'
import ActionCableLink from 'graphql-ruby-client/subscriptions/ActionCableLink'
// Create the apollo client
export default function createApolloClient ({ ssr, endpoints, persisting, subscriptions }) {
let link = new HttpLink({
uri: endpoints.graphql,
credentials: 'same-origin' // MUST HAVE for CSRF validation via Rails
})
// HTTP Auth header injection
const authLink = setContext((_, { headers }) => ({
headers: {
...headers,
// Fetch CSRF from head via html embed from Rails
'X-CSRF-Token': document.querySelector('meta[name=csrf-token]').getAttribute('content')
}
}))
// Concat all the http link parts
link = authLink.concat(link)
if (persisting) {
link = createPersistedQueryLink().concat(link)
}
// Apollo cache
const cache = new InMemoryCache()
if (!ssr) {
// If on the client, recover the injected state
if (typeof window !== 'undefined') {
// eslint-disable-next-line no-underscore-dangle
const state = window.__APOLLO_STATE__
if (state) {
// If you have multiple clients, use `state.<client_id>`
cache.restore(state.defaultClient)
}
}
// Web socket // AC: set up the action cable link point
if (subscriptions) {
// Create the subscription websocket link
const wsClient = ActionCable.createConsumer(endpoints.subscription)
const wsLink = new ActionCableLink({cable: wsClient})
link = split(
// split based on operation type
({ query }) => {
const { kind, operation } = getMainDefinition(query)
return kind === 'OperationDefinition' &&
operation === 'subscription'
},
wsLink,
link
)
}
}
const apolloClient = new ApolloClient({
link,
cache,
connectToDevTools: true,
// Additional options
...(ssr ? {
// Set this on the server to optimize queries when SSR
ssrMode: true
} : {
// This will temporary disable query force-fetching
ssrForceFetchDelay: 100,
// Apollo devtools
connectToDevTools: process.env.NODE_ENV !== 'production'
})
})
return apolloClient
}
class LampsappSchema < GraphQL::Schema
use GraphQL::Subscriptions::ActionCableSubscriptions
subscription(Types::SubscriptionType)
end
{
"dependencies": {
"actioncable": "^5.2.0",
"graphql-ruby-client": "^1.4.0"
}
}
class Types::SubscriptionType < Types::BaseObject
field :project_updated, Types::ProjectType, 'Some project was updated', null: false do
argument :project_id, ID, required: true
end
# example with authorization and error raising, you should probably make a helper method
def project_updated(project_id:)
project = Project.find(project_id)
authorize project
end
# Something like this should go in BaseObject
def authorize(project)
return project if some_check?
raise GraphQL::ExecutionError.new("Can't subscribe to this project: #{project}")
end
end
import Vue from 'vue'
import createApolloClient from './apollo'
import VueApollo from 'vue-apollo'
// Install the vue plugin
Vue.use(VueApollo)
// Config
const options = {
ssr: false,
endpoints: {
graphql: 'http://YOUR_HOST_NAME/graphql', // you should use absolute URLs for endpoints
subscription: 'ws://YOUR_HOST_NAME/cable'
},
persisting: false,
subscriptions: true
}
// Create apollo client
export const apolloClient = createApolloClient(options)
// Create vue apollo provider
export const apolloProvider = new VueApollo({
defaultClient: apolloClient
})
@johansmitsnl
Copy link

Did you got it to work in a project? I find the documentation hard to read and maybe you have a project where I can take a peek?
Do you have to write a subscription type for each field or can it be done generic?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment