https://github.com/coditory/go-di
Go Dependency Injection library
https://github.com/coditory/go-di
Last synced: 2 months ago
JSON representation
Go Dependency Injection library
- Host: GitHub
- URL: https://github.com/coditory/go-di
- Owner: coditory
- License: mit
- Created: 2023-02-23T11:38:53.000Z (about 3 years ago)
- Default Branch: main
- Last Pushed: 2025-12-15T10:05:12.000Z (4 months ago)
- Last Synced: 2025-12-18T10:04:23.415Z (4 months ago)
- Language: Go
- Size: 104 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Contributing: .github/CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# Coditory - Go Dependency Injection
[](https://github.com/coditory/go-di/releases)
[](https://pkg.go.dev/github.com/coditory/go-di)
[](https://goreportcard.com/report/github.com/coditory/go-di)
[](https://github.com/coditory/go-di/actions?query=workflow%3ABuild+branch%3Amain)
[](https://codecov.io/gh/coditory/go-di)
**🚧 This library as under heavy development until release of version `1.x.x` 🚧**
> Dependency injection for Go projects, targeted for web applications that create DI context during the startup and operates on collections of dependencies.
- Register dependencies by name and type
- Register multiple dependencies per type
- Conditional dependency registration
- Simple dependency retrieval - no manual casting or additional callbacks
- Simple setup - no generators
- Detection of slow dependency creation (TODO)
- Initialization and finalization mechanisms (TODO)
# Getting started
## Installation
Get the dependency with:
```sh
go get github.com/coditory/go-di
```
and import it in the project:
```go
import "github.com/coditory/go-di"
```
The exported package is `di`, basic usage:
```go
import "github.com/coditory/go-di"
func main() {
ctxb := di.NewContextBuilder()
// Add dependencies
ctxb.Add(&foo)
// Build the di context
ctx := ctxb.Build()
// Retrieve dependencies from the context
}
```
## Full example
```go
package main
import (
"fmt"
"github.com/coditory/go-di"
)
type Baz interface { Id() string }
type Foo struct { id string }
func (f *Foo) Id() string { return f.id }
type Bar struct { id string }
func (b *Bar) Id() string { return b.id }
func main() {
foo := Foo{id: "foo1"}
foo2 := Foo{id: "foo2"}
bar := Bar{id: "baz"}
ctxb := di.NewContextBuilder()
ctxb.AddAs(new(Baz), &foo)
ctxb.AddAs(new(Baz), &foo2)
ctxb.AddAs(new(Baz), &bar)
ctx := ctxb.Build()
fmt.Printf("first implementation: %+v\n", di.Get[Baz](ctx))
for i, baz := range di.GetAll[Baz](ctx) {
fmt.Printf("%d: %+v\n", i, baz)
}
}
// output:
// first implementation: &{id:foo1}
// 0: &{id:foo1}
// 1: &{id:foo2}
// 2: &{id:baz}
```
# Usage
## Dependencies by type
Add dependency reference and retrieve by the reference type:
```go
ctxb := di.NewContextBuilder()
ctxb.Add(&foo)
ctxb.Add(&foo2)
ctx := ctxb.Build()
suite.Equal(&foo, di.Get[*Foo](ctx))
suite.Equal([]*Foo{&foo, &foo2}, di.GetAll[*Foo](ctx))
```
Add dependency (by value) and retrieve by the type:
```go
ctxb := di.NewContextBuilder()
ctxb.Add(foo)
ctxb.Add(foo2)
ctx := ctxb.Build()
suite.Equal(foo, di.Get[Foo](ctx))
foos := di.GetAll[Foo](ctx)
suite.Equal(2, len(foos))
suite.Equal("foo", foos[0].Id())
suite.Equal("foo2", foos[1].Id())
```
## Dependencies by interface
To retrieve a dependency by the interface it must be registered explicitly by the interface type:
```go
ctxb := di.NewContextBuilder()
// ctx.Add(&foo) <- will not work!
ctxb.AddAs(new(Baz), &foo)
ctxb.AddAs(new(Baz), &foo2)
ctx := ctxb.Build()
suite.Equal(&foo, di.Get[Baz](ctx))
suite.Equal([]Baz{&foo, &foo2}, di.GetAll[Baz](ctx))
```
Single dependency can be registered multiple times:
```go
ctxb := di.NewContextBuilder()
ctxb.Add(&foo)
ctxb.AddAs(new(Baz), &foo)
ctxb.Add(&foo2)
ctxb.AddAs(new(Baz), &foo2)
ctx := ctxb.Build()
suite.Equal(&foo, di.Get[Baz](ctx))
suite.Equal([]Baz{&foo, &foo2}, di.GetAll[Baz](ctx))
suite.Equal(&foo, di.Get[*Foo](ctx))
suite.Equal([]*Foo{&foo, &foo2}, di.GetAll[*Foo](ctx))
```
## Named dependencies
To differentiate dependencies of the same type you can name them.
There can be only one dependency per name.
```go
ctxb := di.NewContextBuilder()
ctxb.AddAs(new(Baz), &foo)
ctxb.AddNamedAs("special-foo", new(Baz), &foo2)
// ctxb.AddNamedAs("special-foo", new(Baz), &foo3) <- panics
ctx := ctxb.Build()
suite.Equal(&foo, di.Get[Baz](ctx))
suite.Equal(&foo2, di.GetNamed[Baz](ctx, "special-foo"))
suite.Equal([]Baz{&foo, &foo2}, di.GetAll[Baz](ctx))
```
## Lazy dependencies
Lazy dependencies are created when retrieved:
```go
type Boo struct {
foo *Foo
bar *Bar
}
ctxb := di.NewContextBuilder()
ctxb.Provide(func() *Foo {
return &foo
})
ctxb.Provide(func() *Bar {
return &bar
})
ctxb.Provide(func(foo *Foo, bar *Bar) *Boo {
return &Boo{foo: foo, bar: bar}
})
ctx := ctxb.Build()
boo := di.Get[*Boo](ctx)
suite.Equal(&foo, boo.foo)
suite.Equal(&bar, boo.bar)
```
If a dependency requires a long list of other dependencies then inject `*Context`:
```go
ctxb.Provide(func(ctx *di.Context) *Boo {
return &Boo{foo: di.Get[*Foo](ctx), bar: di.Get[*Bar](ctx)}
})
```
There are the same variations for `ctxb.Add*` and `ctxb.Provide*` functions:
```go
ctxb.Provide(createFoo)
ctxb.ProvideAs(new(Baz), createFoo)
ctxb.ProvideNamed("special-foo", createFoo)
ctxb.ProvideNamedAs("special-foo", new(Baz), createFoo)
```
When dependency creator is a separate (non-inlined) function, then creation happens only once:
```go
creations := 0
createFoo := func() *Foo {
creations++
return &foo
}
ctxb := di.NewContextBuilder()
ctxb.Provide(createFoo)
ctxb.ProvideAs(new(Baz), createFoo)
ctx := ctxb.Build()
di.Get[Baz](ctx)
di.Get[*Foo](ctx)
suite.Equal(1, creations)
```