Announcing kiwi

Dependency injection for Dart and Flutter

Romain Rastel
Sep 9, 2018 · 5 min read

Today, I’m very pleased to announce kiwi, a dependency injection library for Dart and Flutter which aims to be simple and fast.

Why?

Even if I’m writing a small application, I tend to separate the logic from the UI. Because projects grow, I think it’s a good practice to do this if the project is not a proof of concept.

I like to have small services with one responsibility. It’s easier to test, to maintain, to read, to understand. A problem with this principle is that you end up with services having a lot of dependencies. Creating such a service can be tedious if you have to instantiate all the dependencies before calling the constructor. In most of the cases, you can rely on IoC libraries to do this for you and most of them use reflection at runtime to create an object.

But since Flutter cannot run code that depends on dart:mirrors, we cannot use Dart libraries that lies on reflection to create objects.

So I looked for IoC libraries that we can use in Flutter. Here are the 3 most promising libraries (for me) and why I didn’t use them:

  • inject: The package is offered as-is, and I found it too complicated for my needs (I never used Dagger).
  • get_it: It’s a really good Service Locator library, but it does not provide a generator in case we want to use it for constructor injection.
  • dioc: This is the one that almost fit my needs, but it didn’t support Dart 2 at the time I started my own package. Some other features I wanted were not implemented either.

After this little research, I found the need to create my own library (which is heavily inspired by dioc and get_it) and I ended up sharing it with you now 🙂.

What is kiwi?

At its very core, kiwi is simply a container of instances and factories you can name. It’s coupled with a powerful generator to allow the developer to write less code.

The generator provided by kiwi only supports constructor injection in order to minimize the code that depends on it.

Another important thing is that kiwi only works with Dart ≥ 2.0.0.

Library usage

The core of kiwi is the Container class. This is where all your instances and factories are stored.

The Container is implemented as a singleton. You can access the single instance like this:

Note: I promise you, even if this is looking like a constructor, you will always end up with the same instance 😉.

The container can store instances, factories, and singletons. What I name singleton here, is a factory that will be called only once, after which the same instance will be provided every time.

Instances can be registered like this:

Factories like that:

And for singletons, you just have to change Factory by Singleton:

Note: The c parameter is the instance of the Container, we will saw later how it can be useful.

Then, you can get the value registered under a specified type like this:

Now if you have a service that depends on another, add the dependency in the constructor. For registering this service, you can then use the c parameter of the factory to get the value.

For services with a lot of dependencies, it can be tedious to write that sort of code. That’s why kiwi comes with a generator 😃!

Generator usage

The generator let the developer write less code. By using the generator, you minimize also the maintenance cost. When a dependency is added to a service, you just have to run the generator.

The generator handles factories and singletons, but not instances. Only const instances can appear in metadata, so it would be awkward to support only const instances here.

Let’s see how to use it:

  • l3: You have to create a part directive. The value of this directive is simply the name of your file with a .g before the dart extension.
  • l5: You have to create an abstract class where all abstract methods are annotated with at least one @Register metadata.
  • l6: Annotation for registering a singleton for the type ServiceA.
  • l7: Annotation for registering a factory that will create a Service from a ServiceB.
  • l8: Annotation for registering a factory for ServiceB with the name factoryB.
  • l9: Annotation for registering a factory for ServiceC and by specifying to use the factoryB factory for the ServiceB dependency.
  • l10: Annotation for registering a factory for ServiceC, and by specifying to use the ServiceC.other constructor.
  • l28: The call to the generated class to register all the types.

The following code represents the generated file:

You can set as many register methods as you want. For example, you can have a method per environment and one method for registering everything that is common:

This is very simple and modular, isn’t it?

Conclusion

This library contains two packages you can now download on pub: kiwi, which contains the container and the annotations, and kiwi_generator which is, as indicated by its name, the generator. I hope it will be as useful to you as it is for me.

You’ll find more details in the GitHub repository (like how to configure your project to use the generator).

Feedbacks are welcome 😃. If you find bugs, please issue them in the GitHub issues page.

If this package is helping you, you can support me by ⭐️the repository, or 👏 this story.
You can also follow me on Twitter.

Flutter Community

Articles and Stories from the Flutter Community

Romain Rastel

Written by

Flutter addict

Flutter Community

Articles and Stories from the Flutter Community

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade