2

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 console when graphql server down

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!

NULL pointer
  • 1,116
  • 1
  • 14
  • 27

0 Answers0