Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example Implementation for React-Native/Rails/GraphQl/Apollo #5

Open
ccfz opened this issue Jul 31, 2019 · 4 comments
Open

Example Implementation for React-Native/Rails/GraphQl/Apollo #5

ccfz opened this issue Jul 31, 2019 · 4 comments

Comments

@ccfz
Copy link

ccfz commented Jul 31, 2019

We did not find any solutions for our stack React-Native/Rails/GraphQl/Apollo and specifically had problems creating an ActionCable that connected properly with GraphQL subscriptions. The solution was a combination of this very nice package (thanks @kesha-antonov!!) and adjusting graphql-ruby ActionCableLink to work with the interface of react-native-action-cable. In case anyone else is having trouble with this stack I thought it might be nice to see a working example. Maybe in the README or example folder etc.

index.js

/**
 * @format
 */

import React from 'react';
import { ActionCable, Cable } from '@kesha-antonov/react-native-action-cable';
import { ApolloProvider } from 'react-apollo';
import { ApolloClient } from 'apollo-client';
import { ApolloLink } from 'apollo-link';
import { AppRegistry } from 'react-native';
import { createHttpLink } from 'apollo-link-http';
import { getMainDefinition } from 'apollo-utilities';
import { InMemoryCache } from 'apollo-cache-inmemory';

import AppWithNavigator from './src/navigators';
import { name as appName } from './app.json';
import ActionCableLink from './src/helpers/ActionCableLink';

const httpLink = createHttpLink({ uri: 'http://localhost:3000/graphql' });
const actionCable = ActionCable.createConsumer('ws://localhost:3000/cable');
const cable = new Cable({});

const hasSubscriptionOperation = ({ query }) => {
  const { kind, operation } = getMainDefinition(query);

  return kind === 'OperationDefinition' && operation === 'subscription';
};

const link = ApolloLink.split(
  hasSubscriptionOperation,
  new ActionCableLink({ actionCable, cable }),
  httpLink
);

const client = new ApolloClient({
  link,
  cache: new InMemoryCache()
});

const AppWithApollo = () => (
  <ApolloProvider client={client}>
    <AppWithNavigator />
  </ApolloProvider>
);

AppRegistry.registerComponent(appName, () => AppWithApollo);

adjusted ActionCableLink.js

import { ApolloLink, Observable } from 'apollo-link';

const printer = require('graphql/language/printer');

function ActionCableLink(options) {
  const { cable, actionCable } = options;
  const { connectionParams = {} } = options;
  const channelName = options.channelName || 'GraphqlChannel';
  const actionName = options.actionName || 'execute';

  return new ApolloLink(operation => (
    new Observable((observer) => {
      const channelId = Math.round(
        Date.now() + Math.random() * 100000
      ).toString(16);

      const channel = cable.setChannel(
        'GraphqlChannel', // channel name to which we will pass data from Rails app with `stream_from`
        actionCable.subscriptions.create({
          channel: channelName,
          channelId,
          ...connectionParams
        })
      );

      /* eslint-disable func-names */
      channel.on('connected', function () {
        this.perform(
          actionName,
          {
            query: operation.query ? printer.print(operation.query) : null,
            variables: operation.variables,
            operationId: operation.operationId,
            operationName: operation.operationName
          }
        );
      }).on('received', function (payload) {
        if (payload.result.data || payload.result.errors) {
          observer.next(payload.result);
        }

        if (!payload.more) {
          this.unsubscribe();
          observer.complete();
        }
      });

      /* eslint-enable func-names */

      return channel;
    })
  ));
}

module.exports = ActionCableLink;
@ccfz ccfz changed the title Example Implementation with Rails/GraphQl/Apollo Example Implementation for React-Native/Rails/GraphQl/Apollo Jul 31, 2019
@kesha-antonov
Copy link
Owner

@ccfz awesome! Thank you!

@javiercr
Copy link

This worked for us too, thanks @ccfz!

@developius
Copy link

Thank you @ccfz, this is awesome. Without this, my subscriptions weren't initially connecting without triggering a refresh or navigation in RN. Very strange.

@glundgrenm
Copy link

Solution still working in 2022. Thanks a lot!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants