do

package module
v2.0.0-beta.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 4, 2023 License: MIT Imports: 18 Imported by: 208

README ΒΆ

do - Dependency Injection

tag Go Version GoDoc Build Status Go report Coverage License

βš™οΈ A dependency injection toolkit based on Go 1.18+ Generics.

This library implements the Dependency Injection design pattern. It may replace the uber/dig fantastic package. samber/do uses Go 1.18+ generics instead of reflection and therefore offers a typesafe API.

See also:

  • samber/lo: A Lodash-style Go library based on Go 1.18+ Generics
  • samber/mo: Monads based on Go 1.18+ Generics (Option, Result, Either...)

Why this name?

I love the short name for such a utility library. This name is the sum of DI and Go and no Go package uses this name.

πŸ”₯ Migration from v1 to v2

Documentation here

πŸ’‘ Features

  • πŸ“’ Service registration
    • By type inference
    • By name
  • πŸͺƒ Service invocation
    • Eager loading
    • Lazy loading
    • Transient loading
  • πŸ§™β€β™‚οΈ Service aliasing
    • Implicit (provide struct, invoke interface)
    • Explicit (provide struct, bind interface, invoke interface)
  • πŸ” Service lifecycle
    • Health check
    • Graceful unload (shutdown)
    • Lifecycle hooks
  • πŸ“¦ Scope (a.k.a module) tree
    • Visibility control
    • Dependency grouping
  • πŸ“€ Injector
    • Dependency graph resolution and visualization
    • Default injector
    • Injector cloning
    • Service override
  • 🌈 Lightweight, no dependencies
  • πŸ”… No code generation
  • 😷 Typesafe API

πŸš€ Install

# v2 (latest)
go get github.com/samber/do@v2

# v1
go get github.com/samber/do

This library is v2 and follows SemVer strictly.

No breaking changes will be made to exported APIs before v3.0.0.

This library has no dependencies except the Go std lib.

🀠 Documentation

πŸ›© Benchmark

// @TODO

🀝 Contributing

Don't hesitate ;)

# Install some dev dependencies
make tools

# Run tests
make test
# or
make watch-test

πŸ‘€ Contributors

Contributors

πŸ’« Show your support

Give a ⭐️ if this project helped you!

GitHub Sponsors

πŸ“ License

Copyright Β© 2022 Samuel Berthe.

This project is MIT licensed.

Documentation ΒΆ

Index ΒΆ

Examples ΒΆ

Constants ΒΆ

View Source
const DefaultRootScopeName = "[root]"

Variables ΒΆ

View Source
var ErrCircularDependency = errors.New("DI: circular dependency detected")
View Source
var ErrHealthCheckTimeout = errors.New("DI: health check timeout")
View Source
var ErrServiceNotFound = errors.New("DI: could not find service")

Functions ΒΆ

func As ΒΆ

func As[Initial any, Alias any](i Injector) error

As declares an alias for a service.

func AsNamed ΒΆ

func AsNamed[Initial any, Alias any](i Injector, initial string, alias string) error

AsNamed declares a named alias for a named service.

func DescribeInjector ΒΆ

func DescribeInjector(scope Injector) (output string, ok bool)

DescribeInjector returns a human readable description of the injector, with services and scope tree.

func DescribeNamedService ΒΆ

func DescribeNamedService[T any](scope Injector, name string) (output string, ok bool)

DescribeNamedService returns a human readable description of the service. It returns false if the service is not found. Please call Invoke[T] before DescribeNamedService[T] to ensure that the service is registered.

func DescribeService ΒΆ

func DescribeService[T any](i Injector) (output string, ok bool)

DescribeService returns a human readable description of the service. It returns false if the service is not found. Please call Invoke[T] before DescribeService[T] to ensure that the service is registered.

func ExampleInjector_Clone ΒΆ

func ExampleInjector_Clone()

func ExampleInjector_HealthCheck ΒΆ

func ExampleInjector_HealthCheck()

func ExampleInjector_ListInvokedServices_invoked ΒΆ

func ExampleInjector_ListInvokedServices_invoked()

func ExampleInjector_ListInvokedServices_notInvoked ΒΆ

func ExampleInjector_ListInvokedServices_notInvoked()

func ExampleInjector_ListProvidedServices ΒΆ

func ExampleInjector_ListProvidedServices()

func ExampleInjector_Shutdown ΒΆ

func ExampleInjector_Shutdown()

func ExplainNamedService ΒΆ

func ExplainNamedService(scope Injector, name string) (dependencies []EdgeService, dependents []EdgeService, ok bool)

ExplainNamedService returns a list of dependencies and dependents of a named service.

func ExplainService ΒΆ

func ExplainService[T any](scope Injector) (dependencies []EdgeService, dependents []EdgeService, ok bool)

ExplainService returns a list of dependencies and dependents of a service.

func HealthCheck ΒΆ

func HealthCheck[T any](i Injector) error

HealthCheck returns a service status, using type inference to determine the service name.

func HealthCheckNamed ΒΆ

func HealthCheckNamed(i Injector, name string) error

HealthCheckNamed returns a service status.

func HealthCheckNamedWithContext ΒΆ

func HealthCheckNamedWithContext(ctx context.Context, i Injector, name string) error

HealthCheckNamedWithContext returns a service status.

func HealthCheckWithContext ΒΆ

func HealthCheckWithContext[T any](ctx context.Context, i Injector) error

HealthCheckWithContext returns a service status, using type inference to determine the service name.

func Invoke ΒΆ

func Invoke[T any](i Injector) (T, error)

Invoke invokes a service in the DI container, using type inference to determine the service name.

Example ΒΆ
injector := New()

type test struct {
	foobar string
}

Provide(injector, func(i Injector) (*test, error) {
	return &test{foobar: "foobar"}, nil
})
value, err := Invoke[*test](injector)

fmt.Println(value)
fmt.Println(err)
Output:

&{foobar}
<nil>

func InvokeAs ΒΆ

func InvokeAs[T any](i Injector) (T, error)

InvokeAs invokes a service in the DI container. The first service matching the provided type or interface will be invoked.

func InvokeNamed ΒΆ

func InvokeNamed[T any](i Injector, name string) (T, error)

InvokeNamed invokes a named service in the DI container.

Example ΒΆ
injector := New()

type test struct {
	foobar string
}

ProvideNamed(injector, "my_service", func(i Injector) (*test, error) {
	return &test{foobar: "foobar"}, nil
})
value, err := InvokeNamed[*test](injector, "my_service")

fmt.Println(value)
fmt.Println(err)
Output:

&{foobar}
<nil>

func MustAs ΒΆ

func MustAs[Initial any, Alias any](i Injector)

MustAs declares an alias for a service. It panics on error.

func MustAsNamed ΒΆ

func MustAsNamed[Initial any, Alias any](i Injector, initial string, alias string)

AsNamed declares a named alias for a named service. It panics on error.

func MustInvoke ΒΆ

func MustInvoke[T any](i Injector) T

MustInvoke invokes a service in the DI container, using type inference to determine the service name. It panics on error.

Example ΒΆ
injector := New()

type test struct {
	foobar string
}

Provide(injector, func(i Injector) (*test, error) {
	return &test{foobar: "foobar"}, nil
})
value := MustInvoke[*test](injector)

fmt.Println(value)
Output:

&{foobar}

func MustInvokeAs ΒΆ

func MustInvokeAs[T any](i Injector) T

MustInvokeAs invokes a service in the DI container. The first service matching the provided type or interface will be invoked. It panics on error.

func MustInvokeNamed ΒΆ

func MustInvokeNamed[T any](i Injector, name string) T

MustInvokeNamed invokes a named service in the DI container. It panics on error.

Example ΒΆ
injector := New()

type test struct {
	foobar string
}

ProvideNamed(injector, "my_service", func(i Injector) (*test, error) {
	return &test{foobar: "foobar"}, nil
})
value := MustInvokeNamed[*test](injector, "my_service")

fmt.Println(value)
Output:

&{foobar}

func MustShutdown ΒΆ

func MustShutdown[T any](i Injector)

MustShutdown stops a service, using type inference to determine the service name. It panics on error.

func MustShutdownNamed ΒΆ

func MustShutdownNamed(i Injector, name string)

MustShutdownNamed stops a named service. It panics on error.

func MustShutdownNamedWithContext ΒΆ

func MustShutdownNamedWithContext(ctx context.Context, i Injector, name string)

MustShutdownNamedWithContext stops a named service. It panics on error.

func MustShutdownWithContext ΒΆ

func MustShutdownWithContext[T any](ctx context.Context, i Injector)

MustShutdownWithContext stops a service, using type inference to determine the service name. It panics on error.

func NameOf ΒΆ

func NameOf[T any]() string

NameOf returns the name of the service in the DI container. This is higly discouraged to use this function, as your code should not declare any dependency explicitly.

func Override ΒΆ

func Override[T any](i Injector, provider Provider[T])

Override replaces the service in the DI container, using type inference to determine the service name.

Example ΒΆ
injector := New()

type test struct {
	foobar string
}

Provide(injector, func(i Injector) (*test, error) {
	return &test{foobar: "foobar1"}, nil
})
Override(injector, func(i Injector) (*test, error) {
	return &test{foobar: "foobar2"}, nil
})
value, err := Invoke[*test](injector)

fmt.Println(value)
fmt.Println(err)
Output:

&{foobar2}
<nil>

func OverrideNamed ΒΆ

func OverrideNamed[T any](i Injector, name string, provider Provider[T])

OverrideNamed replaces the named service in the DI container.

Example ΒΆ
injector := New()

type test struct {
	foobar string
}

ProvideNamed(injector, "my_service", func(i Injector) (*test, error) {
	return &test{foobar: "foobar1"}, nil
})
OverrideNamed(injector, "my_service", func(i Injector) (*test, error) {
	return &test{foobar: "foobar2"}, nil
})
value, err := InvokeNamed[*test](injector, "my_service")

fmt.Println(value)
fmt.Println(err)
Output:

&{foobar2}
<nil>

func OverrideNamedTransient ΒΆ

func OverrideNamedTransient[T any](i Injector, name string, provider Provider[T])

OverrideNamedTransient replaces the named factory in the DI container.

func OverrideNamedValue ΒΆ

func OverrideNamedValue[T any](i Injector, name string, value T)

OverrideNamedValue replaces the named value in the DI container.

Example ΒΆ
injector := New()

type test struct {
	foobar string
}

ProvideNamedValue(injector, "my_service", &test{foobar: "foobar1"})
OverrideNamedValue(injector, "my_service", &test{foobar: "foobar2"})
value, err := InvokeNamed[*test](injector, "my_service")

fmt.Println(value)
fmt.Println(err)
Output:

&{foobar2}
<nil>

func OverrideTransient ΒΆ

func OverrideTransient[T any](i Injector, provider Provider[T])

OverrideTransient replaces the factory in the DI container, using type inference to determine the service name.

func OverrideValue ΒΆ

func OverrideValue[T any](i Injector, value T)

OverrideValue replaces the value in the DI container, using type inference to determine the service name.

func Provide ΒΆ

func Provide[T any](i Injector, provider Provider[T])

Provide registers a service in the DI container, using type inference.

Example ΒΆ
injector := New()

type test struct {
	foobar string
}

Provide(injector, func(i Injector) (*test, error) {
	return &test{foobar: "foobar"}, nil
})
value, err := Invoke[*test](injector)

fmt.Println(value)
fmt.Println(err)
Output:

&{foobar}
<nil>

func ProvideNamed ΒΆ

func ProvideNamed[T any](i Injector, name string, provider Provider[T])

ProvideNamed registers a named service in the DI container.

Example ΒΆ
injector := New()

type test struct {
	foobar string
}

ProvideNamed(injector, "my_service", func(i Injector) (*test, error) {
	return &test{foobar: "foobar"}, nil
})
value, err := InvokeNamed[*test](injector, "my_service")

fmt.Println(value)
fmt.Println(err)
Output:

&{foobar}
<nil>

func ProvideNamedTransient ΒΆ

func ProvideNamedTransient[T any](i Injector, name string, provider Provider[T])

ProvideNamedTransient registers a named factory in the DI container.

func ProvideNamedValue ΒΆ

func ProvideNamedValue[T any](i Injector, name string, value T)

ProvideNamedValue registers a named value in the DI container.

Example ΒΆ
injector := New()

type test struct {
	foobar string
}

ProvideNamedValue(injector, "my_service", &test{foobar: "foobar"})
value, err := InvokeNamed[*test](injector, "my_service")

fmt.Println(value)
fmt.Println(err)
Output:

&{foobar}
<nil>

func ProvideTransient ΒΆ

func ProvideTransient[T any](i Injector, provider Provider[T])

ProvideTransient registers a factory in the DI container, using type inference to determine the service name.

func ProvideValue ΒΆ

func ProvideValue[T any](i Injector, value T)

ProvideValue registers a value in the DI container, using type inference to determine the service name.

Example ΒΆ
injector := New()

type test struct {
	foobar string
}

ProvideValue(injector, &test{foobar: "foobar"})
value, err := Invoke[*test](injector)

fmt.Println(value)
fmt.Println(err)
Output:

&{foobar}
<nil>

func Shutdown ΒΆ

func Shutdown[T any](i Injector) error

Shutdown stops a service, using type inference to determine the service name.

func ShutdownNamed ΒΆ

func ShutdownNamed(i Injector, name string) error

ShutdownNamed stops a named service.

func ShutdownNamedWithContext ΒΆ

func ShutdownNamedWithContext(ctx context.Context, i Injector, name string) error

ShutdownNamedWithContext stops a named service.

func ShutdownWithContext ΒΆ

func ShutdownWithContext[T any](ctx context.Context, i Injector) error

ShutdownWithContext stops a service, using type inference to determine the service name.

Types ΒΆ

type DAG ΒΆ

type DAG struct {
	// contains filtered or unexported fields
}

DAG represents a Directed Acyclic Graph of services, tracking dependencies and dependents.

type EdgeService ΒΆ

type EdgeService struct {
	ScopeID   string
	ScopeName string
	Service   string
}

EdgeService represents a service in the DAG, identified by scope ID, scope name, and service name.

type Healthchecker ΒΆ

type Healthchecker interface {
	HealthCheck() error
}

type HealthcheckerWithContext ΒΆ

type HealthcheckerWithContext interface {
	HealthCheck(context.Context) error
}

type Injector ΒΆ

type Injector interface {
	// api
	ID() string
	Name() string
	Scope(string) *Scope
	RootScope() *RootScope
	Ancestors() []*Scope
	Children() []*Scope
	ChildByID(string) (*Scope, bool)
	ChildByName(string) (*Scope, bool)
	ListProvidedServices() []EdgeService
	ListInvokedServices() []EdgeService
	HealthCheck() map[string]error
	HealthCheckWithContext(context.Context) map[string]error
	Shutdown() error
	ShutdownWithContext(context.Context) error
	// contains filtered or unexported methods
}

Injector is a DI container.

type InjectorOpts ΒΆ

type InjectorOpts struct {
	HookAfterRegistration func(scope *Scope, serviceName string)
	HookAfterShutdown     func(scope *Scope, serviceName string)

	Logf func(format string, args ...any)

	HealthCheckParallelism   uint          // default: all jobs are executed in parallel
	HealthCheckGlobalTimeout time.Duration // default: no timeout
	HealthCheckTimeout       time.Duration // default: no timeout
}

type Provider ΒΆ

type Provider[T any] func(Injector) (T, error)

type RootScope ΒΆ

type RootScope struct {
	// contains filtered or unexported fields
}

RootScope is the first level of scope tree.

var DefaultRootScope *RootScope = New()

func New ΒΆ

func New() *RootScope

New creates a new injector.

func NewWithOpts ΒΆ

func NewWithOpts(opts *InjectorOpts) *RootScope

NewWithOpts creates a new injector with options.

func (*RootScope) Ancestors ΒΆ

func (s *RootScope) Ancestors() []*Scope

func (*RootScope) ChildByID ΒΆ

func (s *RootScope) ChildByID(id string) (*Scope, bool)

func (*RootScope) ChildByName ΒΆ

func (s *RootScope) ChildByName(name string) (*Scope, bool)

func (*RootScope) Children ΒΆ

func (s *RootScope) Children() []*Scope

func (*RootScope) Clone ΒΆ

func (s *RootScope) Clone() *RootScope

Clone clones injector with provided services but not with invoked instances.

func (*RootScope) CloneWithOpts ΒΆ

func (s *RootScope) CloneWithOpts(opts *InjectorOpts) *RootScope

CloneWithOpts clones injector with provided services but not with invoked instances, with options.

func (*RootScope) HealthCheck ΒΆ

func (s *RootScope) HealthCheck() map[string]error

func (*RootScope) HealthCheckWithContext ΒΆ

func (s *RootScope) HealthCheckWithContext(ctx context.Context) map[string]error

func (*RootScope) ID ΒΆ

func (s *RootScope) ID() string

pass through

func (*RootScope) ListInvokedServices ΒΆ

func (s *RootScope) ListInvokedServices() []EdgeService

func (*RootScope) ListProvidedServices ΒΆ

func (s *RootScope) ListProvidedServices() []EdgeService

func (*RootScope) Name ΒΆ

func (s *RootScope) Name() string

func (*RootScope) RootScope ΒΆ

func (s *RootScope) RootScope() *RootScope

func (*RootScope) Scope ΒΆ

func (s *RootScope) Scope(name string) *Scope

func (*RootScope) Shutdown ΒΆ

func (s *RootScope) Shutdown() error

func (*RootScope) ShutdownOnSIGTERM ΒΆ

func (s *RootScope) ShutdownOnSIGTERM() (os.Signal, error)

ShutdownOnSIGTERM listens for sigterm signal in order to graceful stop service. It will block until receiving a sigterm signal.

func (*RootScope) ShutdownOnSIGTERMOrInterrupt ΒΆ

func (s *RootScope) ShutdownOnSIGTERMOrInterrupt() (os.Signal, error)

ShutdownOnSIGTERMOrInterrupt listens for sigterm or interrupt signal in order to graceful stop service. It will block until receiving a sigterm signal.

func (*RootScope) ShutdownOnSIGTERMOrInterruptWithContext ΒΆ

func (s *RootScope) ShutdownOnSIGTERMOrInterruptWithContext(ctx context.Context) (os.Signal, error)

ShutdownOnSIGTERMOrInterruptWithContext listens for sigterm or interrupt signal in order to graceful stop service. It will block until receiving a sigterm signal.

func (*RootScope) ShutdownOnSIGTERMWithContext ΒΆ

func (s *RootScope) ShutdownOnSIGTERMWithContext(ctx context.Context) (os.Signal, error)

ShutdownOnSIGTERMWithContext listens for sigterm signal in order to graceful stop service. It will block until receiving a sigterm signal.

func (*RootScope) ShutdownOnSignals ΒΆ

func (s *RootScope) ShutdownOnSignals(signals ...os.Signal) (os.Signal, error)

ShutdownOnSignals listens for signals defined in signals parameter in order to graceful stop service. It will block until receiving any of these signal. If no signal is provided in signals parameter, syscall.SIGTERM will be added as default signal.

func (*RootScope) ShutdownOnSignalsWithContext ΒΆ

func (s *RootScope) ShutdownOnSignalsWithContext(ctx context.Context, signals ...os.Signal) (os.Signal, error)

ShutdownOnSignalsWithContext listens for signals defined in signals parameter in order to graceful stop service. It will block until receiving any of these signal. If no signal is provided in signals parameter, syscall.SIGTERM will be added as default signal.

func (*RootScope) ShutdownWithContext ΒΆ

func (s *RootScope) ShutdownWithContext(ctx context.Context) error

type Scope ΒΆ

type Scope struct {
	// contains filtered or unexported fields
}

Scope is a DI container. It must be created with injector.Scope("name") method.

func (*Scope) Ancestors ΒΆ

func (s *Scope) Ancestors() []*Scope

Ancestors returns the list of parent scopes recursively.

func (*Scope) ChildByID ΒΆ

func (s *Scope) ChildByID(id string) (*Scope, bool)

ChildByID returns the child scope recursively by its ID.

func (*Scope) ChildByName ΒΆ

func (s *Scope) ChildByName(name string) (*Scope, bool)

ChildByName returns the child scope recursively by its name.

func (*Scope) Children ΒΆ

func (s *Scope) Children() []*Scope

Children returns the list of immediate child scopes.

func (*Scope) HealthCheck ΒΆ

func (s *Scope) HealthCheck() map[string]error

HealthCheck returns the healthcheck results of the scope, in a map of service name to error.

func (*Scope) HealthCheckWithContext ΒΆ

func (s *Scope) HealthCheckWithContext(ctx context.Context) map[string]error

HealthCheckWithContext returns the healthcheck results of the scope, in a map of service name to error.

func (*Scope) ID ΒΆ

func (s *Scope) ID() string

ID returns the unique identifier of the scope.

func (*Scope) ListInvokedServices ΒΆ

func (s *Scope) ListInvokedServices() []EdgeService

ListInvokedServices returns the list of services invoked by the scope.

func (*Scope) ListProvidedServices ΒΆ

func (s *Scope) ListProvidedServices() []EdgeService

ListProvidedServices returns the list of services provided by the scope.

func (*Scope) Name ΒΆ

func (s *Scope) Name() string

Name returns the name of the scope.

func (*Scope) RootScope ΒΆ

func (s *Scope) RootScope() *RootScope

RootScope returns the root scope.

func (*Scope) Scope ΒΆ

func (s *Scope) Scope(name string) *Scope

Scope creates a new child scope.

func (*Scope) Shutdown ΒΆ

func (s *Scope) Shutdown() error

Shutdown shutdowns the scope and all its children.

func (*Scope) ShutdownWithContext ΒΆ

func (s *Scope) ShutdownWithContext(ctx context.Context) error

ShutdownWithContext shutdowns the scope and all its children.

type Service ΒΆ

type Service[T any] interface {
	// contains filtered or unexported methods
}

type ServiceAlias ΒΆ

type ServiceAlias[Initial any, Alias any] struct {
	// contains filtered or unexported fields
}

type ServiceEager ΒΆ

type ServiceEager[T any] struct {
	// contains filtered or unexported fields
}

type ServiceLazy ΒΆ

type ServiceLazy[T any] struct {
	// contains filtered or unexported fields
}

type ServiceTransient ΒΆ

type ServiceTransient[T any] struct {
	// contains filtered or unexported fields
}

type ServiceType ΒΆ

type ServiceType string
const (
	ServiceTypeLazy      ServiceType = "lazy"
	ServiceTypeEager     ServiceType = "eager"
	ServiceTypeTransient ServiceType = "transient"
	ServiceTypeAlias     ServiceType = "alias"
)

type Shutdowner ΒΆ

type Shutdowner interface {
	Shutdown()
}

type ShutdownerWithContext ΒΆ

type ShutdownerWithContext interface {
	Shutdown(context.Context)
}

type ShutdownerWithContextAndError ΒΆ

type ShutdownerWithContextAndError interface {
	Shutdown(context.Context) error
}

type ShutdownerWithError ΒΆ

type ShutdownerWithError interface {
	Shutdown() error
}

Directories ΒΆ

Path Synopsis
examples
dag command
healthcheckable command
interface command
nested-scope command
shutdownable command
simple command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL