I'm trying to set up a graphcool subscription / websockets as per this tutorial at How To GraphQL but I'm getting the following message:
WebSocket connection to 'wss://subscriptions.graph.cool/v1/###' failed: WebSocket is closed before the connection is established.
I'm seem to have everything as per the tutorial. Do you have any idea why the websockets connection is not being established?
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './components/App'
import registerServiceWorker from './registerServiceWorker'
import './styles/index.css'
import { ApolloProvider, createNetworkInterface, ApolloClient } from 'react-apollo'
import { SubscriptionClient, addGraphQLSubscriptions } from 'subscriptions-transport-ws'
import { BrowserRouter } from 'react-router-dom'
import { GC_AUTH_TOKEN } from './constants'
const networkInterface = createNetworkInterface({
uri: 'https://api.graph.cool/simple/v1/###'
})
const wsClient = new SubscriptionClient('wss://subscriptions.graph.cool/v1/###', {
reconnect: true,
connectionParams: {
authToken: localStorage.getItem(GC_AUTH_TOKEN),
}
})
const networkInterfaceWithSubscriptions = addGraphQLSubscriptions(
networkInterface,
wsClient
)
networkInterface.use([{
applyMiddleware(req, next) {
if (!req.options.headers) {
req.options.headers = {}
}
const token = localStorage.getItem(GC_AUTH_TOKEN)
req.options.headers.authorization = token ? `Bearer ${token}` : null
next()
}
}])
const client = new ApolloClient({
networkInterface: networkInterfaceWithSubscriptions
})
ReactDOM.render(
<BrowserRouter>
<ApolloProvider client={client}>
<App />
</ApolloProvider>
</BrowserRouter>
, document.getElementById('root')
)
registerServiceWorker()
App.js
import React, { Component } from 'react'
import LinkList from './LinkList'
import CreateLink from './CreateLink'
import Header from './Header'
import Login from './Login'
import Search from './Search'
import { Switch, Route, Redirect } from 'react-router-dom'
class App extends Component {
render() {
return (
<div className='center w85'>
<Header />
<div className='ph3 pv1 background-gray'>
<Switch>
<Route exact path='/search' component={Search}/>
<Route exact path='/' component={LinkList}/>
<Route exact path='/create' component={CreateLink}/>
<Route exact path='/login' component={Login}/>
</Switch>
</div>
</div>
)
}
}
export default App
LinkList.js
import React, { Component } from 'react'
import Link from './Link'
import { graphql, gql } from 'react-apollo'
class LinkList extends Component {
_updateCacheAfterVote = (store, createVote, linkId) => {
const data = store.readQuery({ query: ALL_LINKS_QUERY })
const votedLink = data.allLinks.find(link => link.id === linkId)
votedLink.votes = createVote.link.votes
store.writeQuery({ query: ALL_LINKS_QUERY, data })
}
componentDidMount() {
this._subscribeToNewLinks()
this._subscribeToNewVotes()
}
render() {
if (this.props.allLinksQuery && this.props.allLinksQuery.loading) {
return <div>Loading</div>
}
if (this.props.allLinksQuery && this.props.allLinksQuery.error) {
return <div>Error</div>
}
const linksToRender = this.props.allLinksQuery.allLinks
return (
<div>
{linksToRender.map((link, index) => (
<Link key={link.id} updateStoreAfterVote={this._updateCacheAfterVote} index={index} link={link}/>
))}
</div>
)
}
_subscribeToNewLinks = () => {
this.props.allLinksQuery.subscribeToMore({
document: gql`
subscription {
Link(filter: {
mutation_in: [CREATED]
}) {
node {
id
url
description
createdAt
postedBy {
id
name
}
votes {
id
user {
id
}
}
}
}
}
`,
updateQuery: (previous, { subscriptionData }) => {
const newAllLinks = [
subscriptionData.data.Link.node,
...previous.allLinks
]
const result = {
...previous,
allLinks: newAllLinks
}
return result
}
})
}
_subscribeToNewVotes = () => {
this.props.allLinksQuery.subscribeToMore({
document: gql`
subscription {
Vote(filter: {
mutation_in: [CREATED]
}) {
node {
id
link {
id
url
description
createdAt
postedBy {
id
name
}
votes {
id
user {
id
}
}
}
user {
id
}
}
}
}
`,
updateQuery: (previous, { subscriptionData }) => {
const votedLinkIndex = previous.allLinks.findIndex(link => link.id === subscriptionData.data.Vote.node.link.id)
const link = subscriptionData.data.Vote.node.link
const newAllLinks = previous.allLinks.slice()
newAllLinks[votedLinkIndex] = link
const result = {
...previous,
allLinks: newAllLinks
}
return result
}
})
}
}
export const ALL_LINKS_QUERY = gql`
query AllLinksQuery {
allLinks {
id
createdAt
url
description
postedBy {
id
name
}
votes {
id
user {
id
}
}
}
}
`
export default graphql(ALL_LINKS_QUERY, { name: 'allLinksQuery' }) (LinkList)
Can you add the timeout
parameter to your client configuration like this:
const wsClient = new SubscriptionClient('wss://subscriptions.graph.cool/v1/###', {
reconnect: true,
timeout: 30000,
connectionParams: {
authToken: localStorage.getItem(GC_AUTH_TOKEN),
}
})
There's a slight mismatch between the subscription-transport-ws
client implementation and the Graphcool subscription server implementation how keep-alives are handled, and the long timeout period fixes it.
Read this issue on GitHub and this Graphcool feature request for more background information.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With