godi

package module
v3.0.1 Latest Latest
Warning

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

Go to latest
Published: Jul 28, 2025 License: MIT Imports: 13 Imported by: 0

README ΒΆ

godi - Dependency Injection for Go

Go Reference Go Report Card License

godi makes dependency injection in Go simple and familiar. If you've used .NET's DI container, you'll feel right at home.

Quick Start

package main

import (
    "fmt"
    "github.com/junioryono/godi/v3"
)

// 1. Define your service
type Greeter struct {
    name string
}

func NewGreeter() *Greeter {
    return &Greeter{name: "World"}
}

func (g *Greeter) Greet() string {
    return fmt.Sprintf("Hello, %s!", g.name)
}

func main() {
    // 2. Register your services
    services := godi.NewServiceCollection()
    services.AddSingleton(NewGreeter)

    // 3. Build the container
    provider, _ := services.BuildServiceProvider()
    defer provider.Close()

    // 4. Use your service
    greeter, _ := godi.Resolve[*Greeter](provider)
    fmt.Println(greeter.Greet()) // Output: Hello, World!
}

Why godi?

Problem: Your Go app is growing. Adding a new dependency to a service means updating every place that creates it. Testing requires complex setup. Sound familiar?

Solution: godi automatically wires your dependencies. Change a constructor in one place, godi handles the rest.

Real Example: Adding a Logger

Without godi:

// You have to update EVERY file that creates a UserService
userService := NewUserService()                    // Before
userService := NewUserService(logger)              // After - updating 20+ files!

With godi:

// Just update the constructor - godi handles the rest
func NewUserService(logger Logger) *UserService {  // godi injects the logger
    return &UserService{logger: logger}
}

Core Features

🎯 Two Service Lifetimes
  • Singleton: One instance for the entire app (databases, loggers)
  • Scoped: New instance per request/operation (web handlers, transactions)
services.AddSingleton(NewDatabase)    // Shared across app
services.AddScoped(NewUserService)    // Fresh per request
πŸ§ͺ Testing Made Easy

Swap real services with mocks instantly:

// In tests
services.AddSingleton(func() Database {
    return &MockDatabase{
        users: []User{{ID: 1, Name: "Test User"}},
    }
})

// Your code uses the mock automatically!
πŸ”Œ Zero Magic
  • Your services are just normal Go types
  • No struct tags, no code generation
  • Full IDE support with Go generics

Installation

go get github.com/junioryono/godi/v3

Common Patterns

Web Application
func main() {
    services := godi.NewServiceCollection()

    // Register services
    services.AddSingleton(NewLogger)
    services.AddSingleton(NewDatabase)
    services.AddScoped(NewUserRepository)

    provider, _ := services.BuildServiceProvider()
    defer provider.Close()

    // Use with your web framework
    http.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {
        // Create a scope for this request
        scope := provider.CreateScope(r.Context())
        defer scope.Close()

        // Services are isolated per request
        repo, _ := godi.Resolve[*UserRepository](scope)
        // ... handle request
    })
}
Service Dependencies
// godi automatically injects dependencies
func NewUserService(repo UserRepository, logger Logger) *UserService {
    return &UserService{
        repo:   repo,
        logger: logger,
    }
}

// Just register - godi figures out the order
services.AddSingleton(NewLogger)
services.AddScoped(NewUserRepository)
services.AddScoped(NewUserService)
Interfaces for Flexibility
type Cache interface {
    Get(key string) (string, error)
    Set(key string, value string) error
}

// Easy to swap implementations
services.AddSingleton(func() Cache {
    if config.UseRedis {
        return NewRedisCache()
    }
    return NewMemoryCache()
})

Documentation

When to Use godi

βœ… Use godi when:

  • You're building web APIs or services
  • You need request-scoped isolation
  • You want easy unit testing
  • You're tired of manual dependency wiring

❌ Skip godi when:

  • Building simple CLI tools
  • Your app has < 5 services
  • You prefer manual control

Contributing

We welcome contributions! See CONTRIBUTING.md for guidelines.

License

MIT License - see LICENSE for details.

Documentation ΒΆ

Index ΒΆ

Constants ΒΆ

This section is empty.

Variables ΒΆ

View Source
var (
	// Service resolution errors.
	ErrServiceNotFound             = errors.New("service not found")
	ErrServiceKeyNil               = errors.New("service key cannot be nil")
	ErrInvalidServiceType          = errors.New("invalid service type")
	ErrFailedToExtractService      = errors.New("failed to extract service")
	ErrFailedToExtractKeyedService = errors.New("failed to extract keyed service")

	// Lifecycle errors.
	ErrDisposed         = errors.New("disposed")
	ErrNilScope         = errors.New("scope cannot be nil")
	ErrScopeDisposed    = errors.New("scope has been disposed")
	ErrProviderDisposed = errors.New("service provider has been disposed")

	// Constructor/registration errors.
	ErrNilConstructor                 = errors.New("constructor cannot be nil")
	ErrNilServiceProvider             = errors.New("service provider cannot be nil")
	ErrConstructorNotFunction         = errors.New("constructor must be a function")
	ErrConstructorNoReturn            = errors.New("constructor must return at least one value")
	ErrConstructorTooManyReturns      = errors.New("constructor must return at most 2 values")
	ErrConstructorInvalidSecondReturn = errors.New("constructor's second return value must be error")
	ErrConstructorMultipleIn          = errors.New("constructor cannot have multiple In parameters")
	ErrConstructorOutMaxReturns       = errors.New("constructor with Out must return at most 2 values")

	// Decorator errors.
	ErrDecoratorNil         = errors.New("decorator cannot be nil")
	ErrDecoratorNotFunction = errors.New("decorator must be a function")
	ErrDecoratorNoParams    = errors.New("decorator must have at least one parameter")
	ErrDecoratorNoReturn    = errors.New("decorator must return at least one value")

	// Collection/descriptor errors.
	ErrCollectionBuilt             = errors.New("service collection has already been built")
	ErrCollectionModifyAfterBuild  = errors.New("cannot modify service collection after build")
	ErrDescriptorNil               = errors.New("descriptor cannot be nil")
	ErrNoConstructorOrDecorator    = errors.New("constructor or decorator must be provided")
	ErrBothConstructorAndDecorator = errors.New("cannot have both constructor and decorator")

	// Provider errors.
	ErrServicesNil                   = errors.New("services cannot be nil")
	ErrProviderFunctionNotFound      = errors.New("provider function not found")
	ErrKeyedProviderFunctionNotFound = errors.New("keyed provider function not found")
	ErrConstructorMustReturnValue    = errors.New("constructor must be a function that returns at least one value")
	ErrServiceHasNoConstructor       = errors.New("service has no constructor")
	ErrDescriptorHasNoConstructor    = errors.New("descriptor has no constructor")
	ErrFailedToCreateScope           = errors.New("failed to create dig scope: dig container is nil")

	// Special cases.
	ErrResultObjectConstructor = errors.New("constructor returns Out - use collection.Add* methods")
	ErrReplaceResultObject     = errors.New("replace not supported for result object constructors")

	// Context errors
	ErrScopeNotInContext = errors.New("no scope found in context")
)
View Source
var As = dig.As

As is an option that specifies that the value produced by the constructor implements one or more other interfaces and should be provided as those interfaces.

Example:

collection.AddSingleton(NewPostgresDB, godi.As(new(Reader), new(Writer)))

This makes the PostgresDB available as both Reader and Writer interfaces.

View Source
var FillDecorateInfo = dig.FillDecorateInfo

FillDecorateInfo is an option that writes information about what dig was able to get out of the provided decorator.

View Source
var FillInvokeInfo = dig.FillInvokeInfo

FillInvokeInfo is an option that writes information about what dig was able to get out of the invoked function.

Example:

var info godi.InvokeInfo
provider.Invoke(myFunc, godi.FillInvokeInfo(&info))
View Source
var FillProvideInfo = dig.FillProvideInfo

FillProvideInfo is an option that writes information about what dig was able to get out of the provided constructor.

Example:

var info godi.ProvideInfo
collection.AddSingleton(NewService, godi.FillProvideInfo(&info))
View Source
var Group = dig.Group

Group is an option for providing values to a group. Groups allow multiple values of the same type to be collected into a slice.

Example:

collection.AddSingleton(NewUserHandler, godi.Group("routes"))
collection.AddSingleton(NewAdminHandler, godi.Group("routes"))
collection.AddSingleton(NewAPIHandler, godi.Group("routes"))

// Then consume all handlers:
type ServerParams struct {
    godi.In
    Handlers []http.Handler `group:"routes"`
}
View Source
var IsIn = dig.IsIn

IsIn checks whether the given struct is a dig.In struct. This is re-exported from dig for convenience.

View Source
var IsOut = dig.IsOut

IsOut checks whether the given struct is a dig.Out struct. This is re-exported from dig for convenience.

View Source
var Name = dig.Name

Name is an option for providing named values. This can be used with collection.AddSingletonInstance and similar methods.

Example:

collection.AddSingletonInstance(redisCache, godi.Name("redis"))
collection.AddSingletonInstance(memCache, godi.Name("memory"))
View Source
var WithDecoratorBeforeCallback = dig.WithDecoratorBeforeCallback

WithDecoratorBeforeCallback returns a DecorateOption for adding a callback that runs before the decorator starts.

View Source
var WithDecoratorCallback = dig.WithDecoratorCallback

WithDecoratorCallback returns a DecorateOption for adding a callback that runs after the decorator finishes.

View Source
var WithProviderBeforeCallback = dig.WithProviderBeforeCallback

WithProviderBeforeCallback returns a ProvideOption for adding a callback that runs before the constructor starts.

View Source
var WithProviderCallback = dig.WithProviderCallback

WithProviderCallback returns a ProvideOption for adding a callback that runs after the constructor finishes.

Example:

collection.AddSingleton(NewService, godi.WithProviderCallback(func(ci godi.CallbackInfo) {
    log.Printf("Service created in %v", ci.Runtime)
}))

Functions ΒΆ

func IsCircularDependency ΒΆ

func IsCircularDependency(err error) bool

IsCircularDependency checks if an error is due to circular dependencies.

func IsDisposed ΒΆ

func IsDisposed(err error) bool

IsDisposed checks if an error indicates a disposed scope or provider.

func IsNotFound ΒΆ

func IsNotFound(err error) bool

IsNotFound checks if an error indicates a service was not found.

func IsTimeout ΒΆ

func IsTimeout(err error) bool

IsTimeout checks if an error is due to a timeout.

func Resolve ΒΆ

func Resolve[T any](s Scope) (T, error)

Resolve is a generic helper function that returns the service as type T.

func ResolveGroup ΒΆ

func ResolveGroup[T any](s Scope, groupName string) ([]T, error)

ResolveGroup is a generic helper function that returns the group services as type []T.

func ResolveKeyed ΒΆ

func ResolveKeyed[T any](s Scope, serviceKey any) (T, error)

ResolveKeyed is a generic helper function that returns the keyed service as type T.

func SetDefaultServiceProvider ΒΆ

func SetDefaultServiceProvider(provider ServiceProvider)

SetDefault sets the default ServiceProvider used by the package-level functions. This is similar to slog.SetDefault.

After this call, package-level functions like Resolve, Invoke, etc. will use this provider. Pass nil to remove the default provider.

Types ΒΆ

type AlreadyRegisteredError ΒΆ

type AlreadyRegisteredError struct {
	ServiceType reflect.Type
}

AlreadyRegisteredError indicates a service type is already registered.

func (AlreadyRegisteredError) Error ΒΆ

func (e AlreadyRegisteredError) Error() string

type BeforeCallback ΒΆ

type BeforeCallback = dig.BeforeCallback

BeforeCallback is a function called before a constructor or decorator runs.

type BeforeCallbackInfo ΒΆ

type BeforeCallbackInfo = dig.BeforeCallbackInfo

BeforeCallbackInfo contains information about a constructor call before it runs.

type Callback ΒΆ

type Callback = dig.Callback

Callback is a function called after a constructor or decorator runs.

type CallbackInfo ΒΆ

type CallbackInfo = dig.CallbackInfo

CallbackInfo contains information about a constructor call.

type CircularDependencyError ΒΆ

type CircularDependencyError struct {
	ServiceType reflect.Type
	Chain       []reflect.Type // If available from parsing the error
	DigError    error          // The underlying dig error
}

CircularDependencyError represents a circular dependency in the container.

func (CircularDependencyError) Error ΒΆ

func (e CircularDependencyError) Error() string

func (CircularDependencyError) Unwrap ΒΆ

func (e CircularDependencyError) Unwrap() error

type DecorateInfo ΒΆ

type DecorateInfo = dig.DecorateInfo

DecorateInfo contains information about a decorated type.

type DecorateOption ΒΆ

type DecorateOption = dig.DecorateOption

DecorateOption modifies the default behavior of Decorate.

type Disposable ΒΆ

type Disposable interface {
	// Close disposes the resource with the provided context.
	// Implementations should respect context cancellation for graceful shutdown.
	Close() error
}

Disposable allows disposal with context for graceful shutdown. Services implementing this interface can perform context-aware cleanup.

Example:

type DatabaseConnection struct {
    conn *sql.DB
}

func (dc *DatabaseConnection) Close() error {
    return dc.conn.Close()
}

type DisposableWithContext ΒΆ

type DisposableWithContext interface {
	// Close disposes the resource with the provided context.
	// Implementations should respect context cancellation for graceful shutdown.
	Close(ctx context.Context) error
}

DisposableWithContext allows disposal with context for graceful shutdown. Services implementing this interface can perform context-aware cleanup.

Example:

type DatabaseConnection struct {
    conn *sql.DB
}

func (dc *DatabaseConnection) Close(ctx context.Context) error {
    done := make(chan error, 1)
    go func() {
        done <- dc.conn.Close()
    }()

    select {
    case err := <-done:
        return err
    case <-ctx.Done():
        return ctx.Err()
    }
}

type In ΒΆ

type In = dig.In

In embeds dig.In to leverage dig's parameter object functionality. When a constructor function accepts a single struct parameter with embedded In, dig will automatically populate all exported fields of that struct with the corresponding services.

This is a direct wrapper around dig.In, so all dig features are supported:

  • `optional:"true"` - Field is optional and won't cause an error if the service is not found
  • `name:"serviceName"` - Field should be resolved as a keyed/named service
  • `group:"groupName"` - Field should be filled from a value group (slice fields only)

Example:

type ServiceParams struct {
    godi.In

    Database *sql.DB
    Logger   Logger `optional:"true"`
    Cache    Cache  `name:"redis"`
    Handlers []http.Handler `group:"routes"`
}

func NewService(params ServiceParams) *Service {
    return &Service{
        db:       params.Database,
        logger:   params.Logger, // might be nil if not registered
        cache:    params.Cache,
        handlers: params.Handlers,
    }
}

The In struct must be embedded anonymously:

type ServiceParams struct {
    godi.In  // βœ“ Correct - anonymous embedding
    // ...
}

type ServiceParams struct {
    In godi.In  // βœ— Wrong - named field
    // ...
}

type Input ΒΆ

type Input = dig.Input

Input contains information on an input parameter of a function.

type InvokeInfo ΒΆ

type InvokeInfo = dig.InvokeInfo

InvokeInfo contains information about an invoked function.

type InvokeOption ΒΆ

type InvokeOption = dig.InvokeOption

InvokeOption modifies the default behavior of Invoke.

type LifetimeConflictError ΒΆ

type LifetimeConflictError struct {
	ServiceType reflect.Type
	Current     ServiceLifetime
	Requested   ServiceLifetime
}

LifetimeConflictError indicates a service is registered with conflicting lifetimes.

func (LifetimeConflictError) Error ΒΆ

func (e LifetimeConflictError) Error() string

type LifetimeError ΒΆ

type LifetimeError struct {
	Value any
}

LifetimeError indicates an invalid service lifetime value.

func (LifetimeError) Error ΒΆ

func (e LifetimeError) Error() string

type MissingConstructorError ΒΆ

type MissingConstructorError struct {
	ServiceType reflect.Type
	Context     string // "service" or "descriptor"
}

MissingConstructorError indicates a service has no constructor.

func (MissingConstructorError) Error ΒΆ

func (e MissingConstructorError) Error() string

type ModuleError ΒΆ

type ModuleError struct {
	Module string
	Cause  error
}

ModuleError wraps errors from module registration.

func (ModuleError) Error ΒΆ

func (e ModuleError) Error() string

func (ModuleError) Unwrap ΒΆ

func (e ModuleError) Unwrap() error

type ModuleOption ΒΆ

type ModuleOption func(ServiceProvider) error

ModuleOption represents a registration action within a module.

func AddDecorator ΒΆ

func AddDecorator(decorator any, opts ...DecorateOption) ModuleOption

AddDecorator creates a ModuleBuilder for adding a decorator.

func AddScoped ΒΆ

func AddScoped(constructor any, opts ...ProvideOption) ModuleOption

AddScoped creates a ModuleBuilder for adding a scoped service.

func AddSingleton ΒΆ

func AddSingleton(constructor any, opts ...ProvideOption) ModuleOption

AddSingleton creates a ModuleBuilder for adding a singleton service.

func NewModule ΒΆ

func NewModule(name string, builders ...ModuleOption) ModuleOption

NewModule creates a new module with the given name and builders. Modules are a way to group related service registrations together.

Example:

var DatabaseModule = godi.NewModule("database",
    godi.AddSingleton(NewDatabaseConnection),
    godi.AddScoped(NewUserRepository),
    godi.AddScoped(NewOrderRepository),
)

var CacheModule = godi.NewModule("cache",
    godi.AddSingleton(cache.New[any]),
    godi.AddSingleton(NewCacheMetrics),
)

var AppModule = godi.NewModule("app",
    DatabaseModule,
    CacheModule,
    godi.AddScoped(NewAppService),
)

type Out ΒΆ

type Out = dig.Out

Out embeds dig.Out to leverage dig's result object functionality. When a constructor returns a struct with embedded Out, each exported field of that struct is registered as a separate service in the container.

This is a direct wrapper around dig.Out, so all dig features are supported:

  • `name:"serviceName"` - Field should be registered as a keyed/named service
  • `group:"groupName"` - Field should be added to a value group

Example:

type ServiceResult struct {
    godi.Out

    UserService  *UserService
    AdminService *AdminService `name:"admin"`
    Handler      http.Handler  `group:"routes"`
}

func NewServices(db *sql.DB) ServiceResult {
    userSvc := newUserService(db)
    adminSvc := newAdminService(db)

    return ServiceResult{
        UserService:  userSvc,
        AdminService: adminSvc,
        Handler:      newAPIHandler(userSvc),
    }
}

Multiple handlers example with groups:

type Handlers struct {
    godi.Out

    UserHandler  http.Handler `group:"routes"`
    AdminHandler http.Handler `group:"routes"`
    APIHandler   http.Handler `group:"routes"`
}

The Out struct must be embedded anonymously:

type ServiceResult struct {
    godi.Out  // βœ“ Correct - anonymous embedding
    // ...
}

type ServiceResult struct {
    Out godi.Out  // βœ— Wrong - named field
    // ...
}

Result objects are automatically handled by the regular Add* methods:

collection.AddSingleton(NewServices) // Each field in ServiceResult is registered

type Output ΒΆ

type Output = dig.Output

Output contains information on an output produced by a function.

type ProvideInfo ΒΆ

type ProvideInfo = dig.ProvideInfo

ProvideInfo contains information about a provided constructor.

type ProvideOption ΒΆ

type ProvideOption = dig.ProvideOption

ProvideOption modifies the default behavior of Provide.

type RegistrationError ΒΆ

type RegistrationError struct {
	ServiceType reflect.Type
	Operation   string // "provide", "decorate", etc.
	Cause       error
}

RegistrationError wraps errors during service registration.

func (RegistrationError) Error ΒΆ

func (e RegistrationError) Error() string

func (RegistrationError) Unwrap ΒΆ

func (e RegistrationError) Unwrap() error

type ResolutionError ΒΆ

type ResolutionError struct {
	ServiceType reflect.Type
	ServiceKey  any // nil for non-keyed services
	Cause       error
}

ResolutionError wraps errors that occur during service resolution.

func (ResolutionError) Error ΒΆ

func (e ResolutionError) Error() string

func (ResolutionError) Unwrap ΒΆ

func (e ResolutionError) Unwrap() error

type Scope ΒΆ

type Scope interface {
	ServiceProvider

	// ID returns the unique ID of this scope.
	ID() string

	// Context returns the context associated with this scope.
	Context() context.Context

	// IsRootScope returns true if this provider is the root scope.
	IsRootScope() bool

	// Parent returns the parent scope of this scope.
	Parent() Scope
}

Scope defines a disposable service scope. Scopes are used to control the lifetime of scoped services.

In web applications, a scope is typically created for each HTTP request, ensuring that services like database connections are properly managed and disposed at the end of the request.

Example:

scope := provider.CreateScope(ctx)
defer scope.Close()

scopedProvider := scope.ServiceProvider()
service, err := godi.Resolve[MyService](scopedProvider)

func ScopeFromContext ΒΆ

func ScopeFromContext(ctx context.Context) (Scope, error)

ScopeFromContext gets the current scope from context.

type ScopeOption ΒΆ

type ScopeOption = dig.ScopeOption

ScopeOption modifies the default behavior of Scope creation.

type ServiceLifetime ΒΆ

type ServiceLifetime int

ServiceLifetime specifies the lifetime of a service in a ServiceCollection. The lifetime determines when instances are created and how they are cached. This maps to dig's scoping model while maintaining Microsoft DI semantics.

const (
	// Singleton specifies that a single instance of the service will be created.
	// The instance is created on first request and cached for the lifetime of the root provider.
	// Singleton services must not depend on Scoped services.
	// In dig terms, this is a service provided at the root container level.
	Singleton ServiceLifetime = iota

	// Scoped specifies that a new instance of the service will be created for each scope.
	// In web applications, this typically means one instance per HTTP request.
	// Scoped services are disposed when their scope is disposed.
	// In dig terms, this is a service provided at the scope level.
	Scoped
)

func (ServiceLifetime) IsValid ΒΆ

func (sl ServiceLifetime) IsValid() bool

IsValid checks if the service lifetime is valid.

func (ServiceLifetime) MarshalJSON ΒΆ

func (sl ServiceLifetime) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler.

func (ServiceLifetime) MarshalText ΒΆ

func (sl ServiceLifetime) MarshalText() ([]byte, error)

MarshalText implements encoding.TextMarshaler.

func (ServiceLifetime) String ΒΆ

func (sl ServiceLifetime) String() string

String returns the string representation of the ServiceLifetime.

func (*ServiceLifetime) UnmarshalJSON ΒΆ

func (sl *ServiceLifetime) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler.

func (*ServiceLifetime) UnmarshalText ΒΆ

func (sl *ServiceLifetime) UnmarshalText(text []byte) error

UnmarshalText implements encoding.TextUnmarshaler.

type ServiceProvider ΒΆ

type ServiceProvider interface {
	// AddModules applies one or more module configurations to the service collection.
	AddModules(modules ...ModuleOption) error

	// AddSingleton registers a service with singleton lifetime.
	// Only one instance is created and shared across all resolutions.
	AddSingleton(constructor any, opts ...ProvideOption) error

	// AddScoped registers a service with scoped lifetime.
	// One instance is created per scope and shared within that scope.
	AddScoped(constructor any, opts ...ProvideOption) error

	// AddService registers a service with the specified lifetime.
	AddService(lifetime ServiceLifetime, constructor any, opts ...ProvideOption) error

	// Replace replaces all registrations of the specified service type.
	Replace(lifetime ServiceLifetime, constructor any, opts ...ProvideOption) error

	// RemoveAll removes all registrations of the specified service type.
	RemoveAll(serviceType reflect.Type) error

	// GetRootScope returns the root scope of the service provider.
	// The root scope is used for singleton services and tracks disposal of singletons.
	// It is also the default scope for resolving services.
	// This scope is created automatically when the provider is built.
	GetRootScope() Scope

	// CreateScope creates a new service scope with the given context.
	// The returned Scope is also a ServiceProvider for that scope.
	CreateScope(ctx context.Context) Scope

	// Resolve gets the service object of the specified type.
	Resolve(serviceType reflect.Type) (any, error)

	// ResolveKeyed gets the service object of the specified type with the specified key.
	ResolveKeyed(serviceType reflect.Type, serviceKey any) (any, error)

	// ResolveGroup gets all services of the specified type registered in a group.
	// This is useful for plugin systems or when you need multiple implementations.
	ResolveGroup(serviceType reflect.Type, groupName string) ([]any, error)

	// IsService determines whether the specified service type is available.
	// This is useful for optional dependencies.
	IsService(serviceType reflect.Type) bool

	// IsKeyedService determines whether the specified keyed service type is available.
	IsKeyedService(serviceType reflect.Type, serviceKey any) bool

	// Decorate provides a decorator for a type that has already been provided in the Scope.
	Decorate(decorator any, opts ...DecorateOption) error

	// Invoke executes a function with dependency injection.
	// All parameters of the function are resolved from the container.
	// The function can optionally return an error.
	Invoke(function any) error

	// IsDisposed returns true if the provider has been disposed.
	IsDisposed() bool

	Disposable
}

ServiceProvider is the main dependency injection container interface. It provides methods to resolve services, create scopes, and dynamically register services.

ServiceProvider is thread-safe and can be used concurrently. Services are resolved lazily on first request.

Example:

provider := godi.NewServiceProvider()
defer provider.Close()

// Register services dynamically
provider.AddSingleton(NewLogger)
provider.AddScoped(NewDatabase)

// Resolve a service
logger, err := godi.Resolve[Logger](provider)
if err != nil {
    log.Fatal(err)
}

func DefaultServiceProvider ΒΆ

func DefaultServiceProvider() ServiceProvider

Default returns the current default ServiceProvider. Returns nil if no default provider has been set.

func NewServiceProvider ΒΆ

func NewServiceProvider() ServiceProvider

NewServiceProvider creates a new empty ServiceProvider that supports dynamic registration.

Example:

provider := godi.NewServiceProvider()
provider.AddSingleton(NewLogger)
provider.AddScoped(NewDatabase)
defer provider.Close()

func NewServiceProviderWithOptions ΒΆ

func NewServiceProviderWithOptions(options *ServiceProviderOptions) ServiceProvider

NewServiceProviderWithOptions creates a new ServiceProvider with custom options.

type ServiceProviderOptions ΒΆ

type ServiceProviderOptions struct {
	// OnServiceResolved is called after a service is successfully resolved.
	// This can be used for logging, metrics, or debugging.
	OnServiceResolved func(serviceType reflect.Type, instance any, duration time.Duration)

	// OnServiceError is called when a service resolution fails.
	// This can be used for error tracking and debugging.
	OnServiceError func(serviceType reflect.Type, err error)

	// ResolutionTimeout sets a timeout for individual service resolutions.
	// 0 means no timeout (default).
	ResolutionTimeout time.Duration

	// DryRun when true, disables actual invocation of constructors (for testing).
	DryRun bool

	// RecoverFromPanics when true, recovers from panics in constructors.
	RecoverFromPanics bool

	// DeferAcyclicVerification defers cycle detection until first invoke.
	DeferAcyclicVerification bool
}

ServiceProviderOptions configures various ServiceProvider behaviors.

type TimeoutError ΒΆ

type TimeoutError struct {
	ServiceType reflect.Type
	Timeout     time.Duration
}

TimeoutError indicates a service resolution timed out.

func (TimeoutError) Error ΒΆ

func (e TimeoutError) Error() string

func (TimeoutError) Is ΒΆ

func (e TimeoutError) Is(target error) bool

type TypeMismatchError ΒΆ

type TypeMismatchError struct {
	Expected reflect.Type
	Actual   reflect.Type
	Context  string // "interface implementation", "type assertion", etc.
}

TypeMismatchError indicates a type assertion or conversion failed.

func (TypeMismatchError) Error ΒΆ

func (e TypeMismatchError) Error() string

type ValidationError ΒΆ

type ValidationError struct {
	ServiceType reflect.Type
	Message     string
}

ValidationError indicates a validation failure.

func (ValidationError) Error ΒΆ

func (e ValidationError) Error() string

Directories ΒΆ

Path Synopsis
internal

Jump to

Keyboard shortcuts

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