Every project, even a simple one, at certain point need proper layer separation. If you separate responsibilities for better testability and robustness, you will end up using some kind of DI.  There is a great article about kiwi (https://medium.com/flutter-community/announcing-kiwi-52ddb3935e6d) which describes the basic DI setup in the Flutter app. In this article, I want to show a more complex way of using kiwi.

Let’s imagine that we have API which has 4 times of requests:

– unauthorised  (data for every user)
– authorised (data for authorised users)
– localized (data based on location and language)
– localized-authorized (data based on localization and language for authorised users)

We can also think of adding request login layer, but it can be skipped for simplicity.

 

We have to create classes for authorised and localized Clients, each of them will extend BaseClient from ‘package:http/http.dart’ and use ‘Client’ from the same package as it’s own dependency:

1. Authorised

  1. Localized

Now we can focus on our injector.dart:

  • first, we register default  Flutter Client (line 7)
  • then we register our AuthorisedClient (line 8), the syntax goes like this:
    @Register.factory (Type, from: OurCustomType, name: “Name used in DI”)
  • then we register LocalizedClient (line 9 – 13)

    An interesting thing happens with AuthorisedocalizedClient. Each of our custom Clients is using Flutter build-in ‘Client’ from http.dart. As our AuthorisedClient and LocalizedClient both extend BaseClient, they are types of Client, thus to register AuthorizedLocalised we can use LocalizedClient and inject our AuthorisedClient as a dependency (line 17).

Now let’s imagine we are having a Data Layer that can be using some API for fetching data or local DB, to implement. We will create an abstract class called DataService

Then we create an implementation class for API service that uses authorisation for fetching data:

Now we can inject  AuthorisedClient into DataService in inject.dart:

Thanks to composition we’ve used in case our DataService will  be changed and will require AuthorisedLocalizedClient all we will have to do is to change line 6 into

resolvers: {Client: ‘AuthorizedLocalized’})

To summaries, Kiwi is a great tool for DI in Flutter. When used properly it gives us a lot of power and freedom making managing our dependencies smooth and easy.