# `get_it`

| Package | Kind | Provides the role | Needs | Choose with |
| --- | --- | --- | --- | --- |
| [`smf_get_it`](https://pub.dev/packages/smf_get_it) | infrastructure | Dependency injection | nothing | `-m get_it` |

`get_it` provides dependency injection with [get_it](https://pub.dev/packages/get_it) 9. The other modules of the app declare the services they generate, and this module registers them in get_it.

## What it adds to the app

The module adds `get_it: ^9.3.0` to the dependencies and generates `lib/core/di/dependencies.dart` with three functions. `createServiceLocator()` returns a service locator whose `resolve` finds the services in the global instance of get_it, `GetIt.instance`. `registerDependencies()` registers the services, and `bootstrap()` awaits it before the first frame. `resetDependencies()` resets get_it with `GetIt.instance.reset()`, for tests that register the services again.

Whichever module provides it, the dependency injection role adds `lib/core/di/service_locator.dart` with the `ServiceLocator` interface and the function `resolve<T>()`, and calls `registerDependencies()` in the DI phase of `bootstrap()`.

In the [guide for coding agents](https://doc.saymyframe.com/guides/coding-agents.md) of the app, the dependency injection role describes the services under "Dependency injection". The module adds how `registerDependencies()` registers a service in get_it, and that no other file in `lib/` imports the package.

## How services are registered

A module declares each service by its type, the function that creates it, the services the function takes, and how long the service lives. `registerDependencies()` picks the get_it call that fits:

| A module declares | `registerDependencies()` calls |
| --- | --- |
| a singleton | `registerSingleton` |
| a singleton that waits for services that are created asynchronously or wait themselves | `registerSingletonWithDependencies` with `dependsOn` |
| a singleton created asynchronously | `registerSingletonAsync`, with `dependsOn` if it waits |
| a lazy singleton | `registerLazySingleton` |
| a factory | `registerFactory` |
| a name for one of several services of a type | `instanceName`, and `InitDependency` to wait for it |
| a function that disposes of a service | `dispose` |

The factory function of each service gets the services it declares from get_it. get_it creates a singleton while it registers it, so every service is registered after the services it takes or waits for. A singleton also waits, without declaring it, for the services it takes that are created asynchronously or wait themselves, directly or through lazy singletons and factories. When some services are created asynchronously, `registerDependencies()` completes once all of them are ready.

When `resetDependencies()` resets get_it, get_it disposes of the services it created, each with its `dispose` function, in the reverse order of their registration, so each service goes before the services it takes. A lazy singleton that nothing resolved is neither created nor disposed of. Then get_it removes every service, so that `registerDependencies()` can register them again.

`dependencies.dart` imports the file of every type and function it names with a prefix of its own, so the names of different modules never clash.

## Using the services

Only the composition file of a feature, `lib/features/<id>/<id>_composition.dart`, takes services from the container with `resolve`, to create what the screens of the feature need, such as a Cubit. Everything else gets its services as parameters of its factory function. See [Services and state](https://doc.saymyframe.com/guides/services.md).

## Choosing it

`smf create` asks which module provides dependency injection and offers None as well. When a module you chose needs dependency injection and `get_it` is the only module that provides it, `smf create` adds `get_it` by itself. To choose it without the question:

```bash
smf create my_app -m get_it
```
