angularapollo-clientapollo-angular

Two endpoints in Apollo Client (Angular)


Beginer here. While using a single endpoint using the default structure made when executing "ng add apollo-angular" works fine, when adding a second one using APOLLO_NAMED_OPTIONS I get two cryptic errors messages. What could be going wrong?

This is my graphql.module.ts file

import {APOLLO_OPTIONS, APOLLO_NAMED_OPTIONS} from 'apollo-angular';
import { InMemoryCache, ApolloLink } from '@apollo/client/core';
import {HttpLink} from 'apollo-angular/http';

const urium = 'https://some.url.here';       //changed for this post
const urips = 'https://some.other.one.here'; //changed for this post


export function createApollo(httpLink: HttpLink) {
  return {
    link: ApolloLink.from([httpLink.create({ uri: urium })]),
    cache: new InMemoryCache()
  }
}


export function createProjectspecApollo(httpLink: HttpLink) {
  return {
    name:'projectspec',
    link: ApolloLink.from([httpLink.create({ uri: urips })]),
    cache: new InMemoryCache()
  }
}

@NgModule({
  providers: [
    {
      provide: APOLLO_OPTIONS,
      useFactory: createApollo,
      deps: [HttpLink]
    },{
      provide: APOLLO_NAMED_OPTIONS,
      useFactory: createProjectspecApollo,
      deps: [HttpLink]
    }
  ]
})
export class GraphQLModule {}

Here is GqlApolloInterfaceService, where I use the client

import { Apollo } from "apollo-angular";



@Injectable({
  providedIn: 'root'
})
export class GqlApolloInterfaceService {
 
  constructor(private apollo:Apollo) { }
  
}

Finaly, my package.json

{
  "name": "frontend",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "~11.0.0",
    "@angular/cdk": "^11.0.1",
    "@angular/common": "~11.0.0",
    "@angular/compiler": "~11.0.0",
    "@angular/core": "~11.0.0",
    "@angular/flex-layout": "^11.0.0-beta.33",
    "@angular/forms": "~11.0.0",
    "@angular/material": "^11.0.1",
    "@angular/platform-browser": "~11.0.0",
    "@angular/platform-browser-dynamic": "~11.0.0",
    "@angular/router": "~11.0.0",
    "@apollo/client": "^3.0.0",
    "apollo-angular": "^2.1.0",
    "apollo-angular-link-http": "^1.11.0",
    "apollo-link-context": "^1.0.20",
    "graphql": "^15.0.0",
    "rxjs": "~6.6.0",
    "tslib": "^2.0.0",
    "zone.js": "~0.10.2"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.1100.1",
    "@angular/cli": "~11.0.1",
    "@angular/compiler-cli": "~11.0.0",
    "@types/jasmine": "~3.6.0",
    "@types/node": "^12.11.1",
    "codelyzer": "^6.0.0",
    "jasmine-core": "~3.6.0",
    "jasmine-spec-reporter": "~5.0.0",
    "karma": "~5.1.0",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage": "~2.0.3",
    "karma-jasmine": "~4.0.0",
    "karma-jasmine-html-reporter": "^1.5.0",
    "protractor": "~7.0.0",
    "ts-node": "~8.3.0",
    "tslint": "~6.1.0",
    "typescript": "~4.0.2"
  }
}

I get two errors: the first one is only shown first, as soon as I add the second pbject in the providers list:

ERROR Error: Uncaught (in promise): Invariant Violation: To initialize Apollo Client, you must specify a 'cache' property in the options object.

Then, if I refresh the page, I get a different one:

ERROR Error: Uncaught (in promise): Error: NG0200: Circular dependency in DI detected for GqlApolloInterfaceService Error: NG0200: Circular dependency in DI detected for GqlApolloInterfaceService

I'm just starting with Apollo Client so it may be something extremely simple, however, I'm getting the impression that the documentation is very vague and not much effort has been put in making it. What could be happening and, most importantly, how can I make it work?

Regards!


Solution

  • I solved it by using the uri() function within the link atribute from the return object of createApollo. My case was that some queries/mutations had to be done to one endpoint and others to a different endpoint. All my queries/mutations are implemented as services as seen here

    First, I made a function operationFilter that acts as a filter by checking the operation name. Then, the uri funtion uses operationFilter to select between the two different endpoints

    My new graphql.module.ts looks like this

    import {NgModule} from '@angular/core';
    import {APOLLO_OPTIONS } from 'apollo-angular';
    import { InMemoryCache, ApolloLink } from '@apollo/client/core';
    import {HttpLink} from 'apollo-angular/http';
    import { setContext } from '@apollo/client/link/context';
    
    const urium = 'https://some.url.here';       //changed for this post
    const urips = 'https://some.other.one.here'; //changed for this post
    
    
    function operationFilter(operationName:string):boolean{  
      if(...) return true;    //queries that should go to one endpoint
      else return false;      //and the others
     }
    
    export function createApollo(httpLink: HttpLink) {
    
        const auth = setContext((operation, context) => {
            ...add some header stuff, like jwt...
        });
    
       return {
           link: ApolloLink.from(
               [
                   auth, 
                   httpLink.create({
                       uri(operation){ 
                           return operationFilter(operation.operationName)? urium : urips;
                       } 
                   })
               ]),
           cache: new InMemoryCache(),
           defaultOptions:{query:{errorPolicy: "all"}}
        } 
    }
    

    More information can be found here

    I guess it's not the most sophisticated solution, but worked. I'll be happy to learn if there is a cleaner way to do this.

    Regards!