I have a device that sends a heartbeat to my Apollo GraphQL server every 30 seconds. I have a React component that subscribes to hbReceived, and displays the most recent heartbeat time. This works fine.
BUT,
If my GraphQL server is down, I want to handle that error. I expect these errors to be returned in the useSubscription() hook's return value error.networkError
property. Instead, I just see client.ts:545 WebSocket connection to 'ws://localhost:4000/graphql' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
in the console, and the error key remains undefined in the useSubscripiton response.
schema.graphql:
type Heartbeat {
id: ID!
heartbeatTime: DateISO8601!
deviceId: ID!
}
type Subscription {
heartbeatReceived(chargePointInstallId: ID!) : Heartbeat
hbReceived(deviceId: ID!): Heartbeat
}
I made a simple version of my app in create-react-app to illustrate this problem:
src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Heartbeat from './Heartbeat';
import { ApolloProvider } from 'react-apollo';
import { ApolloClient } from 'apollo-client';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { WebSocketLink } from 'apollo-link-ws';
const link = new WebSocketLink({
uri: 'ws://localhost:4000/graphql',
options: {
reconnect: true,
}
});
const client = new ApolloClient({
link,
cache: new InMemoryCache()
});
ReactDOM.render(
<React.StrictMode>
<ApolloProvider client = {client}>
<Heartbeat deviceId={1} />
</ApolloProvider>
</React.StrictMode>,
document.getElementById('root')
);
src/Heartbeat.js
import React from 'react';
import './App.css';
import { useSubscription } from 'react-apollo';
import gql from 'graphql-tag';
export default function Heartbeat(props) {
const { loading, data, error} = useSubscription(
gql`
subscription hbReceived($deviceId: ID!) {
hbReceived(deviceId: $deviceId) {
heartbeatTime
}
}`,
{ variables:{ deviceId: `${props.deviceId}`}}
);
let mostRecentHeartbeatTimeStr;
if (error) {
console.log('Error rerturned:');
console.log(error);
mostRecentHeartbeatTimeStr = 'See console for error';
} else if (loading) {
mostRecentHeartbeatTimeStr = 'Waiting for first heartbeat';
} else {
const mostRecentHeartbeatDate = new Date(data.heartbeatReceived.heartbeatTime);
mostRecentHeartbeatTimeStr = 'Last Heartbeat: ' + mostRecentHeartbeatDate.toLocaleString('en-AU',{})
}
return (<div className='device'>
<div className='device-heading'>
Device heartbeat:
</div>
<div className='device-row'>
{mostRecentHeartbeatTimeStr}
</div>
</div>)
}
This is what I see in the console when the graphQL server is down:
WebSocket connection to 'ws://localhost:4000/graphql' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
How do I catch that WebSocket ERR_CONNECTION_REFUSED error and display some nice message to my user?
What I have tried
I have put a connectionCallback in the options for the new WebSocketLink
constructor
parameters(url,{ options: { connectionCallback(error) => { console.log(error);} });
I have tried composing a link with an onError
from import { onError } from "apollo-link-error";
in it, and put { errorPolicy: 'all' }
in my useSubscription call.
The documentation also says the default behaviour is that network errors are treated like GraphQL errors.
I am stuck! Any help appreciated!