graphql-ruby icon indicating copy to clipboard operation
graphql-ruby copied to clipboard

Observer is null for relaySubscriptionHandler

Open apuntovanini opened this issue 4 years ago • 6 comments

Hi @rmosolgo, currently (if I don't get it terribly wrong), createRelaySubscriptionHandler doens't pass an observer to Relay Network layer, resulting in an Uncaught TypeError: Cannot read property 'onNext' of undefined

Offending lines

received: function (payload) {
  // When we get a response, send the update to `observer`
  var result = payload.result;
  if (result && result.errors) {
      // What kind of error stuff belongs here?
      observer.onError(result.errors);
  }
  else if (result) {
      observer.onNext({ data: result.data });
  }
  if (!payload.more) {
      // Subscription is finished
      observer.onCompleted();
  }
}

observer is undefined. Am I doing something wrong? If yes, maybe some additional comments in docs can be helpful (let me know if you accept PR) Thanks!

graphql version: 1.10.5 rails (or other framework): 6 graphql-batch version: 0.5.4 react-relay: 9.0.0 react-relay-network-modern: ^4.2.0`

We're using intepreters, it happens with any query / subscription

GraphQL query

subscription NewMessageSubscription {
    messageCreated {
      id
    }
  }

We use react-relay-network-modern setup as follow:

const subscribeFn = createRelaySubscriptionHandler({
  cable: consumer,
});


const network = new RelayNetworkLayer(
  [
    process.env.NODE_ENV === 'development' ? loggerMiddleware() : null,
    process.env.NODE_ENV === 'development' ? errorMiddleware() : null,
    process.env.NODE_ENV === 'development' ? perfMiddleware() : null,
  ],
  {
    subscribeFn,
  },
);

const source = new RecordSource();
const store = new Store(source);

const environment = new Environment({
  network,
  store,
});

apuntovanini avatar Mar 30 '20 22:03 apuntovanini

It looks like that function expects observer to be given as an argument:

https://github.com/rmosolgo/graphql-ruby/blob/d1ca69a3daf93286c529e8fccb6e108c4370fb5b/javascript_client/src/subscriptions/createActionCableHandler.ts#L16

Could you please share the full error message and backtrace?

let me know if you accept PR

Yes.

rmosolgo avatar Apr 01 '20 14:04 rmosolgo

Sure

TypeError: source.subscribe is not a function
    at new Executor (RelayModernQueryExecutor.js:97)
    at Object.execute (RelayModernQueryExecutor.js:48)
    at RelayModernEnvironment.js:270
    at _subscribe (RelayObservable.js:580)
    at RelayObservable.subscribe (RelayObservable.js:281)
    at RelayObservable.js:196
    at _subscribe (RelayObservable.js:580)
    at RelayObservable.subscribe (RelayObservable.js:281)
    at RelayObservable.js:293
    at _subscribe (RelayObservable.js:580) "

Since subscribeFn is passed to ReactRelayNetworkModern it may also be an issue with how this function is handled by this Network Layer https://github.com/relay-tools/react-relay-network-modern/blob/5cd2699d1418b72f5735c82f4f0dddf4fb9b2407/src/definition.js#L130

The function created by createActionCableHandler seems ok

export type SubscribeFunction = (
  operation: ConcreteBatch,
  variables: Variables,
  cacheConfig: CacheConfig,
  observer: any
) => RelayObservable<QueryPayload> | Disposable;

but observer can't be created with this function's options...

apuntovanini avatar Apr 01 '20 22:04 apuntovanini

just came to report this, see also:

https://github.com/relay-tools/react-relay-network-modern/issues/95

i'm working on a pr locally as well.

modosc avatar Apr 13 '20 16:04 modosc

I've run into this as well. @modosc have you been able to solve this?

dziemid avatar May 12 '20 23:05 dziemid

I was having this error too with subscriptionFn in modern relay. The solution was to add a "subscribe"property , with a "dispose" property too, in the object I was returning in my function.

const setupSubscription = (
    config: any,
    variables: any,
    cacheConfig: any,
    observer: any
  ) => {

  console.log('config: ', config, 'variables: ', variables, 'cacheConfig: ', cacheConfig, 'observer: ', observer);

  const subscriptionClient = new SubscriptionClient(
    'ws://localhost:3333/subscriptions',
    {
      reconnect: true,
      connectionParams: {
        authorization: localStorage.getItem('authToken')
      },
      lazy: true
    },
  );

  const query = config.text;
  const client = subscriptionClient.request({ query, variables });

  console.log('client observable: ', client);
  let subscription: any;
  return {
    subscribe: (observer: any) => {
      console.log('observer: ', observer);
      subscription = client.subscribe(observer);
      observer.start(subscription);
    },
    dispose: () => {
      subscription.unsubscribe();
    },
  };
}

Streeterxs avatar May 23 '20 18:05 Streeterxs

Did anyone solve this? I'm having the same problem with the ActionCable subscription handler. Modifying the returned object to have a subscribe property did not help.

mattbeedle avatar Feb 13 '21 12:02 mattbeedle

Sorry, I'm not sure if this is still a problem 😖 If you run into this again, please open a new issue and we can investigate again!

rmosolgo avatar Aug 28 '23 13:08 rmosolgo