A container for DI and autowiring written in Go. The main purpose is to provide an interface and a default implementation for autowiring. You can use the default implementation or create your own if the requirements of your project are not satisfied.
go get github.com/4strodev/wiring@latest
Yet this library tries to be as simple as possible I tried to create the minimum features to cover the majority of usecases.
There are two kind of lifecycles
- Singleton: These dependencies are instantiated once and then the instance is cached for future resolves.
- The default implementation is 🧵 concurrently safe.
- Transient: Those are dependencies that are always instantiated every time they are resolved.
- Scoped: For scoped dependencies take a look to the
extended
package.
package main
import (
"fmt"
wiring "github.com/4strodev/wiring/pkg"
)
type Abstraction interface {
Greet()
}
type Implementation struct {
}
func (i *Implementation) Greet() {
fmt.Println("Hello world")
}
func main() {
var container = wiring.New()
container.Singleton(func() (Abstraction, error) {
// This resolver is executed just once
fmt.Println("Running resolver")
return &Implementation{}, nil
})
// Resolving dependency
var impl Abstraction
container.Resolve(&impl)
impl.Greet()
var otherImpl Abstraction
container.Resolve(&otherImpl)
otherImpl.Greet()
// Output:
// Running resolver
// Hello world
// Hello world
}
The extended
package contains extensions for containers:
- Derived: A derived container allows you to create containers that inherits resolvers from parent containers. This is a fully functional container which can has their own and Scoped 🚀 dependencies. Allowing you to use container for short living contexts like an http request.
- Must: An interface that instead of returning errors panics.
Token based dependencies allows you to specify dependencies using a custom token. These are performant, because they are not relying in reflection (at all), and allows you to have multiple dependencies of the same type but with different tokens.
package main
import (
"fmt"
wiring "github.com/4strodev/wiring/pkg"
)
type Abstraction interface {
Greet()
}
type Implementation struct {
}
func (i *Implementation) Greet() {
fmt.Println("Hello world")
}
func main() {
var container = wiring.New()
err := container.TransientToken("abstraction", func() (Abstraction, error) {
return &Implementation{}, nil
})
if err != nil {
panic(err)
}
var impl Abstraction
err = container.ResolveToken("abstraction", &impl)
if err != nil {
panic(err)
}
impl.Greet()
}
Do you have massive dependencies? No problem define a struct with exported fields and let the container fill your struct with the dependencies you need.
package main
import (
"fmt"
"log"
wiring "github.com/4strodev/wiring/pkg"
)
type Abstraction interface {
Greet()
}
type Implementation struct {
}
func (i *Implementation) Greet() {
fmt.Println("Hello world")
}
type FillableStruct struct {
Greeter Abstraction // if no tag is specified it is resolved by type
TokenBased Abstraction `wire:"token"`
IgnoredReader io.Reader `wire:",ignore"`
ignoredField string
}
func main() {
var container = wiring.New()
container.Singleton(func() (Abstraction, error) {
// This resolver is executed just once
return &Implementation{}, nil
})
container.SingletonToken("token", func() (Abstraction, error) {
// This resolver is executed just once
return &Implementation{}, nil
})
var fillable FillableStruct
err := container.Fill(&fillable)
if err != nil {
log.Fatal(err)
}
fillable.Greeter.Greet()
fillable.TokenBased.Greet()
}
There are more examples on the documentation
This project was heavily inspired by goloby/container.