0

Configuring Apollo to connect to Hasura and trying to setup a GraphQL subscription does not work. No errors or anything else, just does not work. I have created a simple Angular project (call it Base Demo) and configured Apollo and the subscriptions are indeed working. I am using the same node version and the same libraries and library versions of ngx-admin.

If I use the same exact code to configure GraphQL in ngx-admin (I just cloned the project to be sure I haven't added any code of mine), it just does not work. Nothing is displayed as result of a subscription, but I also do not get any error. The ws connection in the browser console looks exactly the same as in the Base Demo project.

// GraphQLModule.ts
import {NgModule} from '@angular/core';
import {ApolloModule, APOLLO_OPTIONS} from 'apollo-angular';
import {ApolloClientOptions, InMemoryCache, split} from '@apollo/client/core';
import {HttpLink} from 'apollo-angular/http';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { GraphQLWsLink } from '@apollo/client/link/subscriptions';
import { createClient } from 'graphql-ws';
import { getMainDefinition } from '@apollo/client/utilities';

const uri = 'http://localhost:8080/v1/graphql';
const wsUri = 'ws://localhost:8080/v1/graphql';

export function createApollo(httpLink: HttpLink, http: HttpClient): ApolloClientOptions<any> {

var token = "<token>";
   
  const authLink = httpLink.create({
    uri,
    headers: !token ? new HttpHeaders() : 
      new HttpHeaders()
        .set('Authorization', `Bearer ${token}`)
        .set('x-hasura-role', "manager"),
  });

  const wsLink = new GraphQLWsLink(createClient({
    url: wsUri,
    connectionParams: {
      headers: !token ? {} : 
      {
        Authorization: `Bearer ${token}`,
        'x-hasura-role': "user",
      }
    }
  }));

  // The split function takes three parameters:
  //
  // * A function that's called for each operation to execute
  // * The Link to use for an operation if the function returns a "truthy" value
  // * The Link to use for an operation if the function returns a "falsy" value
  const splitLink = split(
    ({ query }) => {
      const definition = getMainDefinition(query);
      return (
        definition.kind === 'OperationDefinition' &&
        definition.operation === 'subscription'
      );
    },
    wsLink,
    authLink,
  );
  
  return {
    cache: new InMemoryCache({
      addTypename: false,
    }),
    link: splitLink,
  };
}

@NgModule({
  exports: [ApolloModule],
  providers: [
    {
      provide: APOLLO_OPTIONS,
      useFactory: createApollo,
      deps: [HttpLink, HttpClient],
    },
  ],
})
export class GraphQLModule {}
// subscription-page.component.ts
import { Component, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import { ApiService } from '../../../services/api.service';

@Component({
  selector: 'app-subscription-page',
  templateUrl: './subscription-page.component.html',
  styleUrls: ['./subscription-page.component.scss']
})
export class SubscriptionPageComponent implements OnInit {

  data: any;
  subscription?: Subscription;

  constructor(
    private api: ApiService,
  ) {}

  ngOnInit(): void {
    this.subscription = this.api.subscribe()
      .subscribe({
        next: (v) => this.data = v,
        error: (e) => console.error(e),
        complete: () => console.info('complete') 
    })
  }

  ngOnDestroy(): void {
    this.subscription?.unsubscribe();
  }

}

Environment:

Node, npm: node v14.21.3 (npm v6.14.18)
OS: Ubuntu 18.04
Browser: Chrome, Firefox
Angular 13.3.12
Nebular 9.1.0-rc.8

Cloning the ngx-admin repo and configuring Apollo there, I expected to have the subscriptions working as in a normal Angular project.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
gbos
  • 503
  • 2
  • 6
  • 28
  • 1
    Do not vandalize your posts by replacing the content with gibberish. Deletion is sufficient., – Cody Gray - on strike Jun 01 '23 at 06:13
  • I am deleting this because I posted with the wrong account. I am trying to post with my good account where I have more reputation, but it won't let me because it is a duplicate. This is why I am trying to replace all the content. Is it possible to move the question and answer to my other account, or to delete it permanently so I can repost? Thanks @cody-gray – gbos Jun 01 '23 at 06:15
  • Hi, yes, that's possible. What you need to do is get your accounts merged. Please see [this Help Center article](https://stackoverflow.com/help/merging-accounts). That will move this question (and answer) to your main account, where you'll maintain ownership of it. – Cody Gray - on strike Jun 01 '23 at 06:29
  • unfortunately, the form doesn't work. Everytime I try to submit, I get an error that I did not insert the second profile link. But I did! It gets deleted on submit basically, or I do not know what is happening. But it does not work. – gbos Jun 01 '23 at 06:39

1 Answers1

1

After wasting more than 8 hrs between last week and today trying to find what was the problem, looking line by line every file and configuration and doing some tests, I have finally found the solution. The culprit is pace-js, that is inlcuded in ngx-admin but in the end I have never used. pace-js tracking the websockets causes some problems, so the solution was to disable that tracking:

(window as any).paceOptions = {
  ajax: {
      trackWebSockets: false
  }
};

Now everything works. I will be actually completely eliminate pace-js as I am not using it anyway.

gbos
  • 503
  • 2
  • 6
  • 28