Dependency injection in Go
I wanted a DI system that allowed solid typing using generics. I also wanted a way that I could do things like routing and CLI subcommands, so I created a way to register a group of types that could then be consumed by something like a router.
package main
import (
"context"
"github.com/poy/go-dependency-injection/pkg/injection"
)
type A interface {
A()
}
type B interface {
B()
}
func init() {
injection.Register[A](
func(ctx context.Context) A {
return &a{
b: injection.Resolve[B](ctx),
}
},
)
}
type a struct {
b B
}
func (a *a) A() {
println("A()")
a.b.B()
}
func init() {
injection.Register[B](
func(ctx context.Context) B {
return &b{}
},
)
}
type b struct {
}
func (b *b) B() {
println("B()")
}
func main() {
ctx := injection.WithInjection(context.Background())
a := injection.Resolve[A](ctx)
a.A()
}
This example demonstrates a CLI with subcommands that register themselves. This doesn't show it, however each subcommand should/could be its own file.
package main
import (
"context"
"os"
"github.com/poy/go-dependency-injection/pkg/injection"
"github.com/spf13/cobra"
)
func main() {
ctx := injection.WithInjection(context.Background())
if err := BuildRoot(ctx).ExecuteContext(ctx); err != nil {
os.Exit(1)
}
}
type SubCommand *cobra.Command
func BuildRoot(ctx context.Context) *cobra.Command {
cmd := &cobra.Command{
Use: "some-cli",
Short: "Some CLI",
Long: "Some CLI",
RunE: func(cmd *cobra.Command, args []string) error {
return cmd.Help()
},
}
for _, subCmd := range injection.Resolve[injection.Group[SubCommand]](ctx).Vals() {
cmd.AddCommand(subCmd)
}
return cmd
}
func init() {
injection.Register[injection.Group[SubCommand]](
func(ctx context.Context) injection.Group[SubCommand] {
return injection.AddToGroup(ctx, buildFooCommand(ctx))
},
)
}
func buildFooCommand(ctx context.Context) SubCommand {
return &cobra.Command{
Use: "foo",
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
println("Foo")
return nil
},
}
}