5

I want to implement GraphQL client in my flutter app. For Dependency injection, I use GetIt library. But when I run the app, it says

'Invalid argument (Object of type HomeGraphQLService is not registered inside GetIt. Did you forget to pass an instance name? (Did you accidentally do GetIt sl=GetIt.instance(); instead of GetIt sl=GetIt.instance;)): HomeGraphQLService'

.

It means GraphQL client did not instantiate somehow, although I registered it in my service locator

Session.dart

abstract class Session {
  String getAccessToken();
}

SessionImpl.dart

class SessionImpl extends Session {
  SharedPreferences sharedPref;

  SessionImpl(SharedPreferences sharedPref) {
    this.sharedPref = sharedPref;
  }

  @override
  String getAccessToken() {
    return sharedPref.getString('access_token') ?? "";
  }

}

GraphQLClientGenerator.dart

class GraphQLClientGenerator {
  Session session;

  GraphQLClientGenerator(Session session) {
    this.session = session;
  }

  GraphQLClient getClient() {
    final HttpLink httpLink = HttpLink('https://xxx/graphql');
    final AuthLink authLink = AuthLink(getToken: () async => 'Bearer ${_getAccessToken()}');
    final Link link = authLink.concat(httpLink);

    return GraphQLClient(link: link, cache: GraphQLCache(store: InMemoryStore()));
  }

  String _getAccessToken() {
    return session.getAccessToken();
  }
}

HomeRepository.dart

abstract class HomeRepository {
  Future<List<Course>> getAllCourseOf(String className, String groupName);
}

HomeRepositoryImpl.dart

class HomeRepositoryImpl extends HomeRepository {

  HomeGraphQLService homeGraphQLService;
  HomeMapper homeMapper;

  HomeRepositoryImpl(HomeGraphQLService homeGraphQLService, HomeMapper homeMapper) {
    this.homeGraphQLService = homeGraphQLService;
    this.homeMapper = homeMapper;
  }

  @override
  Future<List<Course>> getAllCourseOf(String className, String groupName) async {
    final response = await homeGraphQLService.getAllCourseOf(className, groupName);
    return homeMapper.toCourses(response).where((course) => course.isAvailable);
  }

}

HomeGraphQLService.dart

class HomeGraphQLService {
  GraphQLClient graphQLClient;

  HomeGraphQLService(GraphQLClient graphQLClient) {
    this.graphQLClient = graphQLClient;
  }

  Future<SubjectResponse> getAllCourseOf(String className, String groupName) async {
    try {
      final response = await graphQLClient.query(getAllCourseQuery(className, groupName));
      return SubjectResponse.fromJson((response.data));
    }  catch (e) {
      return Future.error(e);
    }
  }
}

GraphQuery.dart

QueryOptions getAllCourseQuery(String className, String groupName) {
  String query = """
    query GetSubject($className: String, $groupName: String) {
      subjects(class: $className, group: $groupName) {
        code
        display
        insights {
          coming_soon
          purchased
        }
      }
    }
    """;

  return QueryOptions(
    document: gql(query),
    variables: <String, dynamic>{
      'className': className,
      'groupName': groupName,
    },
  );
}

ServiceLocator.dart

final serviceLocator = GetIt.instance;

Future<void> initDependencies() async {
  await _initSharedPref();
  _initSession();
  _initGraphQLClient();
  _initGraphQLService();
  _initMapper();
  _initRepository();
}

Future<void> _initSharedPref() async {
  SharedPreferences sharedPref = await SharedPreferences.getInstance();
  serviceLocator.registerSingleton<SharedPreferences>(sharedPref);
}

void _initSession() {
  serviceLocator.registerLazySingleton<Session>(()=>SessionImpl(serviceLocator()));
}

void _initGraphQLClient() {
  serviceLocator.registerLazySingleton<GraphQLClient>(() => GraphQLClientGenerator(serviceLocator()).getClient());
}

void _initGraphQLService() {
  serviceLocator.registerLazySingleton<HomeGraphQLService>(() => HomeGraphQLService(serviceLocator()));
}

void _initMapper() {
  serviceLocator.registerLazySingleton<HomeMapper>(() => HomeMapper());
}

void _initRepository() {
  serviceLocator.registerLazySingleton<HomeRepository>(() => HomeRepositoryImpl(serviceLocator(), serviceLocator()));
}

main.dart

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  SystemChrome.setPreferredOrientations(
    [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown],
  );
  
  await initDependencies();

  runApp(MyApp());
}
Aminul Haque Aome
  • 2,261
  • 21
  • 34
  • Do you access the client from the locator elsewhere in your code before it is instantiated? Meaning do you await the call to initDependencies? – Lee3 Jun 25 '21 at 05:43
  • @Lee3 yes bro. it is called in main() func. Okey I will update the post. – Aminul Haque Aome Jun 25 '21 at 05:55
  • Try registering all non-lazily. – Lee3 Jun 25 '21 at 06:08
  • @Lee3 same issue bro if I register all of them lazily – Aminul Haque Aome Jun 25 '21 at 06:16
  • I could not reproduce as the issue is occurring elsewhere in your code, but try my answer. Pretty sure it will resolve the problem. – Lee3 Jun 25 '21 at 07:04
  • I recently made a little app for GraphQL by using [Ferry](https://pub.dev/packages/ferry) and [GetX](https://pub.dev/packages/get), that app is similar to your app and it is working fine, you can view the [video](https://drive.google.com/file/d/1DKX2b0JX-k0s7XnsNYOhJ8-OQhWeY9D3/view?usp=sharing). So I'd recommend you to use those packages. – Ουιλιαμ Αρκευα Jul 14 '21 at 21:00

1 Answers1

7

I cannot say where exactly it is happening because it is elsewhere in your code where you are accessing the GraphQLService, but the problem is definitely due to the lazy loading. The object has not been created and loaded by the locator before it is being accessed. Try updating ServiceLocator.dart to instantiate the classes during registration, like so:

void _initSession() {
  serviceLocator.registerSingleton<Session>.(SessionImpl(serviceLocator()));
}

void _initGraphQLClient() {
  serviceLocator.registerSingleton<GraphQLClient>(
    GraphQLClientGenerator(serviceLocator()).getClient());
}

void _initGraphQLService() {
  serviceLocator.registerSingleton<HomeGraphQLService>(
    HomeGraphQLService(serviceLocator()));
}

void _initMapper() {
  serviceLocator.registerSingleton<HomeMapper>(HomeMapper());
}

void _initRepository() {
  serviceLocator.registerSingleton<HomeRepository>(
    HomeRepositoryImpl(serviceLocator(), serviceLocator()));
}
Lee3
  • 2,882
  • 1
  • 11
  • 19
  • thanks for your answer. Let me implement this – Aminul Haque Aome Jun 26 '21 at 03:18
  • is it possible, the error is in GraphQLClientGenerator class? as I am using InMemoryStore() for storing cache, may be I am doing something wrong here. what's your opinion? – Aminul Haque Aome Jun 28 '21 at 04:56
  • I don't think so. The error you're seeing should only occur if somewhere in your code, you try to access n object from the `locator` before it has been registered. I don't see that here. A possible cause of this is if your code and/or the packages being used have classes of the same name, and you are inadvertently implementing 2 different ones at each location. – Lee3 Jun 28 '21 at 17:58