kamilkisiela / apollo-angular

A fully-featured, production ready caching GraphQL client for Angular and every GraphQL server 🎁
https://apollo-angular.com
MIT License
1.5k stars 309 forks source link

Getting NullInjectorError for Apollo #1834

Closed boomdizz closed 1 year ago

boomdizz commented 1 year ago

Describe the bug I have been using apollo-angular with @apollo/client in my angular project for communicating with my django backend for graphql queries, mutations and subscriptions. The code worked well with apollo-angular@2.6.0 and @apollo/client@3.3.19. But I am needing to upgrade to the latest versions. In testing with the latest code (apollo-angular@3.7.0 and @apollo/client@4.1.0), I am getting the following error in the UI/browser (the angular compiler compiles fine):

NullInjectorError: NullInjectorError: No provider for Apollo!
    at NullInjector.get (core.mjs:6344:27)
    at R3Injector.get (core.mjs:6771:33)
    at R3Injector.get (core.mjs:6771:33)
    at R3Injector.get (core.mjs:6771:33)
    at injectInjectorOnly (core.mjs:4761:33)
    at Module.ɵɵinject (core.mjs:4765:12)
    at Object.AppModule_Factory [as useFactory] (app.module.ts:64:23)
    at Object.factory (core.mjs:6959:38)
    at R3Injector.hydrate (core.mjs:6872:35)
    at R3Injector.get (core.mjs:6760:33)

and I get a completely blank webpage with that error message in the console log. I am at a complete loss as to how to fix this. The packages I am using are (snippet of package.json):

    "@apollo/client": "^3.7.0",
    "apollo-angular": "^4.1.0",
    "graphql": "^16.6.0",
    "graphql-ws": "^5.11.2",

Earlier I was using subscriptions-transport-ws, but am trying to move to graphql-ws as part of the upgrade. The apollo client setup happens for me in the app.module.ts constructor:

export class AppModule {
  constructor(
    apollo: Apollo,
    private router: Router
  ) {

    const httpLink = new HttpLink({
      uri: "/graphql/"
    });

    const location = window.location
    let ws_uri = (location.protocol == "http:") ? "ws://" : "wss://"
    ws_uri += location.hostname
    ws_uri += (location.port) ? ":" + location.port : ""
    ws_uri += "/graphql/"
    // Create a WebSocket link:
    const wsLink = new WebSocketLink({
      uri: ws_uri,
      options: {
        reconnect: true
      }
    });

    const splitLink = split(
      ({ query }) => {
        const definition = getMainDefinition(query);
        return (
          definition.kind === 'OperationDefinition' &&
          definition.operation === 'subscription'
        );
      },
      wsLink,
      httpLink,
    );

    const authLink = setContext((_, { headers }) => {
      // get the authentication token from local storage if it exists
      const token = localStorage.getItem('token');
      // return the headers to the context so httpLink can read them
      return {
        headers: {
          ...headers,
          authorization: token ? `JWT ${token}` : "",
        }
      }
    });

    apollo.create({
      link: from([authLink, splitLink]),
      cache: new InMemoryCache()
    });
  }
}

Was looking to find out what I can do next to find out if this is a bug or a configuration issue. Would appreciate any help I could get.

To Reproduce Run ng serve and load the webapplication at port 4200.

Expected behavior

For my web application to load in the browser and the login page to present itself.

Environment:

npm list --depth 0 "@apollo/client" "apollo-angular" "graphql" "@angular/core" "@angular/cli" "typescript" unifypoint@0.0.0 /home/amresh/checkout/unifypoint/src/ui/unifypoint ├── @angular/cli@14.2.6 ├── @angular/core@14.2.7 ├── @apollo/client@3.7.0 ├── apollo-angular@4.1.0 ├── graphql@16.6.0 └── typescript@4.8.4

Additional context

TimToplak commented 1 year ago

Did you import ApolloModule from 'apollo-angular' and import it?

import { HttpClientModule } from '@angular/common/http'
import { ApolloModule, APOLLO_OPTIONS } from 'apollo-angular'    // <--- this
import { HttpLink } from 'apollo-angular/http'
import { InMemoryCache } from '@apollo/client/core'

@NgModule({
  imports: [BrowserModule, ApolloModule, HttpClientModule],     // <---- here
  providers: [
    {
      provide: APOLLO_OPTIONS,
      useFactory(httpLink: HttpLink) {
        return {
          cache: new InMemoryCache(),
          link: httpLink.create({
            uri: 'https://48p1r2roz4.sse.codesandbox.io'
          })
        }
      },
      deps: [HttpLink]
    }
  ]
})
export class AppModule {}
boomdizz commented 1 year ago

Yes, I was able to get it to work. As you can see above, I was getting Apollo as a service injection into AppModule which I guess was the old way of doing things. Once I switched over to the new way by declaring a provider as documented in the latest release, the error went away and it started working.

boomdizz commented 1 year ago

Closing the issue. This was a user configuration error.