A dependency injection library that is focused on clean API and flexibility

GoDoc Go Report Card

Dependency injection

DI is a dependency injection library that is focused on clean API and flexibility. DI has two types of top-level abstractions: Container and Resolver. First one is responsible for accepting constructors and instances and creating abstraction bindings out of them. Second implements different instance resolution scenarios against one or more Containers.

Initially this library was heavily inspired by GoLobby Container but since then had a lot of backwards incompatible changes in structure, functionality and API. To install DI simply run in your project directory:

go get github.com/HnH/di

Container

type Container interface {
    Singleton(constructor interface{}, opts ...Option) error
    Instance(instance interface{}, name string) error
    Factory(constructor interface{}, opts ...Option) error
    ListBindings(reflect.Type) (map[string]Binding, error)
    Reset()
}

Singleton

Singleton() method requires a constructor which will return Implementation(s) of Abstraction(s). Constructor will be called once and returned Implementations(s) will later always bound to Abstraction(s) on resolution requests.

err = di.Singleton(func() (Abstraction, SecondAbstraction) {
    return Implementation, SecondImplementation
})

// Singleton may also accept naming option which means that returned Implementation will be available only under provided name
err = di.Singleton(func() (Abstraction) {
    return Implementation
}, di.WithName("customName"))

// Name can be provided for each of the Implementations if there are more than one
err = di.Singleton(func() (Abstraction, SecondAbstraction) {
    return Implementation, SecondImplementation
}, di.WithName("customName", "secondCustomName"))

// If there is only one Implementation returned you may give multiple aliases for it.
err = di.Singleton(func() (Abstraction) {
    return Implementation
}, di.WithName("customName", "secondCustomName"))

Factory

Factory() method requires a constructor which will return exactly one Implementation of exactly one Abstraction. Constructor will be called on each Abstraction resolution request.

err = di.Factory(func() (Abstraction) {
    return Implementation
})

// Factory also optionally accepts naming option which means that returned Implementation will be available only under provided name
err := di.Factory(func() (Abstraction) {
    return Implementation
}, di.WithName("customName"))

Resolver

type Resolver interface {
    With(instances ...interface{}) Resolver
    Resolve(receiver interface{}, opts ...Option) error
    Call(function interface{}, opts ...Option) error
    Fill(receiver interface{}) error
}

Resolve

Resolve() requires a receiver (pointer) of an Abstraction and fills it with appropriate Implementation.

var abs Abstraction
err = di.Resolve(&a)

// Resolution can be done with previously registered names as well
err = di.Resolve(&a, di.WithName("customName"))

Call

The Call() executes as function with resolved Implementation as a arguments.

err = di.Call(func(a Abstraction) {
    // `a` will be an implementation of the Abstraction
})

// returned values can be bound to variables by providing an option
var db Database
err = di.Call(func(a Abstraction) Database {
    return &MySQL{a}
}, di.WithReturn(&db))
// db == &MySQL{a}

Fill

The Fill() method takes a struct (pointer) and resolves its fields. The example below expresses how the Fill() method works.

err = di.Singleton(func() Mailer { return &someMailer{} })

err = di.Singleton(func() (Database, Database) {
    return &MySQL{}, &Redis{} 
}, di.WithName("data", "cache"))

type App struct {
    mailer Mailer    `di:"type"`
    data   Database  `di:"name"`
    cache  Database  `di:"name"`
    x int
}

myApp := App{}

err := container.Fill(&myApp)

// [Typed Bindings]
// `myApp.mailer` will be an implementation of the Mailer interface

// [Named Bindings]
// `myApp.data` will be a MySQL implementation of the Database interface
// `myApp.cache` will be a Redis implementation of the Database interface

// `myApp.x` will be ignored since it has no `di` tag

Alternatively map[string]Type or []Type can be provided. It will be filled with all available implementations of provided Type.

var list []Shape
container.Fill(&list)

// []Shape{&Rectangle{}, &Circle{}}

var list map[string]Shape
container.Fill(&list)

// map[string]Shape{"square": &Rectangle{}, "rounded": &Circle{}} 
Owner
Sergey Treinis
Tech Lead / Golang software engineer
Sergey Treinis
Comments
  • Context propagation API

    Context propagation API

    type Context interface {
        Put(Container) Context
        Container() Container
        Resolver() Resolver
        Raw() context.Context
    }
    

    Context propagation is possible via di.Context abstraction. Quick example:

    var container = di.NewContainer()
    container.Implementation(newCircle())
    
    var (
        ctx = di.Ctx(context.Background).Put(container)
        shp Shape
    )
    
    err = ctx.Resolver().Resolve(&shp) // err == nil
    
  • Global method API changes and global context

    Global method API changes and global context

    type Context interface {
    	SetContainer(Container) Context
    	Container() Container
    	SetResolver(Resolver) Context
    	Resolver() Resolver
    	Raw() context.Context
    }
    
  • Constructor interface. Binding WithFill() option.

    Constructor interface. Binding WithFill() option.

    Constructor implements a Construct() method which is called either after binding to container in case of singleton, either after factory method was called.

  • Fill() can fill inner structs recursively

    Fill() can fill inner structs recursively

    err = di.Singleton(func() (Database, Database) {
        return &MySQL{}, &Redis{} 
    }, di.WithName("data", "cache"))
    
    type App struct {
        inner  struct {
            cache Database `di:"name"`	
        } `di:"recursive"` // will be filled recursively
        another struct {
            cache Database `di:"name"`	
        } // will be ignored
    }
    
    var App = App{}
    err = container.Fill(&myApp)
    
    // `App.inner.cache` will be a Redis implementation of the Database interface
    // `App.another` will be ignored since it has no `di` tag
    
  • Container.Implementation() method API changes

    Container.Implementation() method API changes

    Implementation() receives ready instance and binds it to its REAL type, which means that declared abstract variable type (interface) is ignored.

    var circle Shape = newCircle()
    err = di.Implementation(circle)
    
    // will return error di: no binding found for: di_test.Shape
    var a Shape
    err = di.Resolve(&a)
    
    // will resolve circle
    var c *Circle
    err = di.Resolve(&a)
    
    // also naming options can be used as everywhere
    err = di.Implementation(circle, di.WithName("customName"))
    err = di.Resolve(&c, di.WithName("customName"))
    
  • Container and Resolver interfaces. Resolver can resolve against multiple containers.

    Container and Resolver interfaces. Resolver can resolve against multiple containers.

    func (suite *ResolverSuite) TestResolveMultiContainer() {
    	var (
    		localContainer   = di.NewContainer()
    		localResolver, _ = di.NewResolver(localContainer, suite.container)
    	)
    
    	suite.Require().NoError(suite.container.Singleton(newRectangle))
    	suite.Require().NoError(localContainer.Singleton(newMySQL))
    
    	var s Shape
    	suite.Require().NoError(suite.resolver.Resolve(&s))
    	suite.Require().IsType(&Rectangle{}, s)
    
    	var db Database
    	suite.Require().EqualError(suite.resolver.Resolve(&db), "di: no binding found for: di_test.Database")
    	suite.Require().Nil(db)
    
    	suite.Require().NoError(localResolver.Resolve(&db))
    	suite.Require().IsType(&MySQL{}, db)
    }
    
  • Call() can return variables

    Call() can return variables

    var (
    	str string
    	db  Database
    )
    
    di.Call(func(s Shape) (string, Database, error) {
    	return "mysql", &MySQL{}, nil
    }, di.WithReturn(&str, &db))
    
    suite.Require().Equal("mysql", str)
    suite.Require().IsType(&MySQL{}, db)
    
Dependency Injection and Inversion of Control package

Linker Linker is Dependency Injection and Inversion of Control package. It supports the following features: Components registry Automatic dependency i

Sep 27, 2022
An additive dependency injection container for Golang.

Alice Alice is an additive dependency injection container for Golang. Philosophy Design philosophy behind Alice: The application components should not

Oct 16, 2022
πŸ›  A full-featured dependency injection container for go programming language.

DI Dependency injection for Go programming language. Tutorial | Examples | Advanced features Dependency injection is one form of the broader technique

Dec 31, 2022
A reflection based dependency injection toolkit for Go.

βš’οΈ dig A reflection based dependency injection toolkit for Go. Good for: Powering an application framework, e.g. Fx. Resolving the object graph during

Jan 1, 2023
Go Dependency Injection Framework

Dingo Dependency injection for go Hello Dingo Dingo works very very similiar to Guice Basically one binds implementations/factories to interfaces, whi

Dec 25, 2022
A dependency injection based application framework for Go.

?? Fx An application framework for Go that: Makes dependency injection easy. Eliminates the need for global state and func init(). Installation We rec

Jan 3, 2023
Simple Dependency Injection Container
Simple Dependency Injection Container

?? gocontainer gocontainer - Dependency Injection Container ?? ABOUT Contributors: RafaΕ‚ Lorenz Want to contribute ? Feel free to send pull requests!

Sep 27, 2022
Strict Runtime Dependency Injection for Golang

wire Wire is runtime depedency injection/wiring for golang. It's designed to be strict to avoid your go application running without proper dependency

Sep 27, 2022
Compile-time dependency injection for Go

Dihedral Dihedral is a compile-time injection framework for Go. Getting started > go get -u github.com/dimes/dihedral Create a type you want injected

Jun 1, 2022
Compile-time Dependency Injection for Go

Wire: Automated Initialization in Go Wire is a code generation tool that automates connecting components using dependency injection. Dependencies betw

Jan 2, 2023
Generated dependency injection containers in go (golang)
Generated dependency injection containers in go (golang)

Generation of dependency injection containers for go programs (golang). Dingo is a code generator. It generates dependency injection containers based

Dec 22, 2022
golang-runtime-di is a framework for runtime dependency injection in go

golang-runtime-di description golang-runtime-di is a framework for runtime dependency injection in go. usage quickstart add it to your go.mod: go get

Aug 1, 2022
Golang PE injection on windows

GoPEInjection Golang PE injection on windows See: https://malwareunicorn.org/workshops/peinjection.html Based on Cryptowall's PE injection technique.

Jan 6, 2023
two scripts written in golang that will help you recognize dependency confusion.
two scripts written in golang that will help you recognize dependency confusion.

two scripts written in golang that will help you recognize dependency confusion.

Mar 3, 2022
A builder πŸ”¨ for binding evil program 😈 and normal document 🐣
A builder πŸ”¨ for binding evil program 😈 and normal document 🐣

GoFileBinder A builder ?? for binding evil program ?? and normal document ?? Usage Clone this repo and build GoFileBinder.go first, then start: ./GoFi

Dec 12, 2022
GO2P is a P2P framework, designed with flexibility and simplicity in mind
GO2P is a P2P framework, designed with flexibility and simplicity in mind

go2p golang p2p framework By v-braun - viktor-braun.de. Description GO2P is a P2P framework, designed with flexibility and simplicity in mind. You can

Jan 5, 2023
CryptoPump is a cryptocurrency trading bot that focuses on high speed and flexibility
CryptoPump is a cryptocurrency trading bot that focuses on high speed and flexibility

CryptoPump is a cryptocurrency trading bot that focuses on high speed and flexibility. The algorithms utilize Go Language and WebSockets to react in real-time to market movements based on Bollinger statistical analysis and pre-defined profit margins.

Nov 24, 2022
Code your next Go web project with (a) Mojito! No matter if its an API or a website, go-mojito assists you with dependency injection, simple routing, custom request / response objects and template rendering
 Code your next Go web project with (a) Mojito! No matter if its an API or a website, go-mojito assists you with dependency injection, simple routing, custom request / response objects and template rendering

Go-Mojito is a super-modular library to bootstrap your next Go web project. It can be used for strict API-only purposes as well as server-side renderi

May 1, 2022
How we can run unit tests in parallel mode with failpoint injection taking effect and without injection race

This is a simple demo to show how we can run unit tests in parallel mode with failpoint injection taking effect and without injection race. The basic

Oct 31, 2021
Dec 28, 2022