Documentation
¶
Index ¶
- Constants
- Variables
- func ErrCircularDependency(cycle []string) *errs.Error
- func ErrServiceAlreadyExists(serviceName string) *errs.Error
- func ErrServiceNotFound(serviceName string) *errs.Error
- func ErrTypeMismatch(serviceName string, actual any) *errs.Error
- func HasType[T any](c Vessel) bool
- func HasTypeNamed[T any](c Vessel, name string) bool
- func Inject[T any](c Vessel) (T, error)
- func InjectGroup[T any](c Vessel, group string) ([]T, error)
- func InjectNamed[T any](c Vessel, name string) (T, error)
- func InjectType[T any](c Vessel) (T, error)deprecated
- func MustInject[T any](c Vessel) T
- func MustInjectGroup[T any](c Vessel, group string) []T
- func MustInjectNamed[T any](c Vessel, name string) T
- func MustInjectType[T any](c Vessel) Tdeprecated
- func NewServiceError(serviceName, operation string, cause error) *errs.Error
- func Provide(c Vessel, constructor any, opts ...ConstructorOption) error
- func ProvideConstructor(c Vessel, constructor any, opts ...ConstructorOption) errordeprecated
- func ProvideNamed(c Vessel, name string, constructor any, opts ...ConstructorOption) error
- func ProvideValue[T any](c Vessel, value T, opts ...ConstructorOption) error
- func QueryNames(c Vessel, query ServiceQuery) []string
- type ConstructorOption
- func As(ifaces ...any) ConstructorOption
- func AsGroup(group string) ConstructorOption
- func AsScoped() ConstructorOption
- func AsSingleton() ConstructorOption
- func AsTransient() ConstructorOption
- func WithAliases(names ...string) ConstructorOption
- func WithEager() ConstructorOption
- func WithName(name string) ConstructorOption
- type DependencyGraph
- func (g *DependencyGraph) AddNode(name string, dependencies []string)
- func (g *DependencyGraph) AddNodeWithDeps(name string, deps []di.Dep)
- func (g *DependencyGraph) GetDependencies(name string) []string
- func (g *DependencyGraph) GetDeps(name string) []di.Dep
- func (g *DependencyGraph) GetEagerDependencies(name string) []string
- func (g *DependencyGraph) HasNode(name string) bool
- func (g *DependencyGraph) TopologicalSort() ([]string, error)
- func (g *DependencyGraph) TopologicalSortEagerOnly() ([]string, error)
- type Factory
- type FuncMiddleware
- func (f *FuncMiddleware) AfterResolve(ctx context.Context, name string, service any, err error) error
- func (f *FuncMiddleware) AfterStart(ctx context.Context, name string, err error) error
- func (f *FuncMiddleware) BeforeResolve(ctx context.Context, name string) error
- func (f *FuncMiddleware) BeforeStart(ctx context.Context, name string) error
- type In
- type Lazy
- type Middleware
- type OptionalLazy
- type Out
- type Provider
- type RegisterOption
- type Scope
- type ServiceInfo
- type ServiceQuery
- type Vessel
Constants ¶
const ( // CodeInvalidFactory indicates a factory function is invalid or nil CodeInvalidFactory = "INVALID_FACTORY" // CodeServiceAlreadyExists indicates a service is already registered CodeServiceAlreadyExists = "SERVICE_ALREADY_EXISTS" // CodeServiceNotFound indicates a service was not found in the container CodeServiceNotFound = "SERVICE_NOT_FOUND" // CodeServiceError indicates an error occurred during service operation CodeServiceError = "SERVICE_ERROR" // CodeCircularDependency indicates a circular dependency was detected CodeCircularDependency = "CIRCULAR_DEPENDENCY" // CodeScopeEnded indicates operation on an ended scope CodeScopeEnded = "SCOPE_ENDED" // CodeTypeMismatch indicates a type mismatch during service resolution CodeTypeMismatch = "TYPE_MISMATCH" )
Variables ¶
var ErrCircularDependencySentinel = errs.NewError(CodeCircularDependency, "circular dependency", nil)
ErrCircularDependencySentinel is a sentinel error for circular dependency (for error checking).
var ErrInvalidFactory = errs.NewError(CodeInvalidFactory, "factory cannot be nil", nil)
ErrInvalidFactory is returned when a nil or invalid factory is provided.
var ErrScopeEnded = errs.NewError(CodeScopeEnded, "scope has ended", nil)
ErrScopeEnded is returned when operations are attempted on an ended scope.
var ErrServiceNotFoundSentinel = errs.NewError(CodeServiceNotFound, "service not found", nil)
ErrServiceNotFoundSentinel is a sentinel error for service not found (for error checking).
var ErrTypeMismatchSentinel = errs.NewError(CodeTypeMismatch, "type mismatch", nil)
ErrTypeMismatchSentinel is a sentinel error for type mismatch during resolution.
Functions ¶
func ErrCircularDependency ¶
ErrCircularDependency creates an error for circular dependency detection
func ErrServiceAlreadyExists ¶
ErrServiceAlreadyExists creates an error for when a service is already registered
func ErrServiceNotFound ¶
ErrServiceNotFound creates an error for when a service is not found
func ErrTypeMismatch ¶
ErrTypeMismatch creates an error for type mismatch during resolution
func HasTypeNamed ¶
HasTypeNamed checks if a named service of the given type is registered.
func InjectGroup ¶
InjectGroup resolves all services in a group as a slice.
Example:
handlers, err := InjectGroup[Handler](c, "http")
func InjectNamed ¶
InjectNamed resolves a named service by its type. Use this when you have multiple implementations of the same type.
Example:
primaryDB, err := InjectNamed[*Database](c, "primary") replicaDB, err := InjectNamed[*Database](c, "replica")
func InjectType
deprecated
func MustInject ¶
MustInject resolves a service by its type, panicking on error.
func MustInjectGroup ¶
MustInjectGroup resolves all services in a group, panicking on error.
func MustInjectNamed ¶
MustInjectNamed resolves a named service by its type, panicking on error.
func MustInjectType
deprecated
func NewServiceError ¶
NewServiceError creates an error for service operations
func Provide ¶
func Provide(c Vessel, constructor any, opts ...ConstructorOption) error
Provide registers a constructor function with automatic dependency resolution. Dependencies are inferred from function parameters and all return types (except error) are registered as services.
This follows the Uber dig pattern for constructor-based dependency injection:
- Function parameters become dependencies (resolved by type)
- Return types become provided services
- Error return type is handled for construction failures
Example:
// Simple constructor
func NewUserService(db *Database, logger *Logger) *UserService {
return &UserService{db: db, logger: logger}
}
Provide(c, NewUserService)
// Constructor with error
func NewDatabase(config *Config) (*Database, error) {
return sql.Open(config.Driver, config.DSN)
}
Provide(c, NewDatabase)
// Using In struct for many dependencies
type ServiceParams struct {
vessel.In
DB *Database
Logger *Logger `optional:"true"`
}
func NewService(p ServiceParams) *Service {
return &Service{db: p.DB, logger: p.Logger}
}
Provide(c, NewService)
func ProvideConstructor
deprecated
func ProvideConstructor(c Vessel, constructor any, opts ...ConstructorOption) error
Deprecated: Use Provide instead.
func ProvideNamed ¶
func ProvideNamed(c Vessel, name string, constructor any, opts ...ConstructorOption) error
ProvideNamed registers a named constructor function with automatic dependency resolution. This is equivalent to calling Provide with WithName(name).
Example:
ProvideNamed(c, "primary", NewPrimaryDB) ProvideNamed(c, "replica", NewReplicaDB)
func ProvideValue ¶
func ProvideValue[T any](c Vessel, value T, opts ...ConstructorOption) error
ProvideValue registers a pre-built instance as a singleton service. The instance is registered by its type and can be resolved with Inject[T].
Example:
cfg := &Config{Port: 8080}
ProvideValue(c, cfg)
// Later:
config, _ := Inject[*Config](c)
func QueryNames ¶
func QueryNames(c Vessel, query ServiceQuery) []string
QueryNames returns the names of services matching the query criteria. This is more efficient than Query when you only need service names.
Example:
// Find all service names in the "db" group
names := vessel.QueryNames(c, vessel.ServiceQuery{
Group: "db",
})
Types ¶
type ConstructorOption ¶
type ConstructorOption interface {
// contains filtered or unexported methods
}
ConstructorOption configures how a constructor is registered
func As ¶
func As(ifaces ...any) ConstructorOption
As registers the constructor result as additional interface types. This enables resolving the service by its interface types.
Example:
Provide(c, NewMyService, As(new(Reader), new(Writer)))
func AsGroup ¶
func AsGroup(group string) ConstructorOption
AsGroup adds the constructor result to a value group. Services in the same group can be resolved together as a slice.
Example:
Provide(c, NewUserHandler, AsGroup("handlers"))
Provide(c, NewProductHandler, AsGroup("handlers"))
handlers := InjectGroup[Handler](c, "handlers") // Returns []Handler
func AsScoped ¶
func AsScoped() ConstructorOption
AsScoped makes the constructor result scoped to request lifetime.
func AsSingleton ¶
func AsSingleton() ConstructorOption
AsSingleton makes the constructor result a singleton (default).
func AsTransient ¶
func AsTransient() ConstructorOption
AsTransient makes the constructor create a new instance on each resolve.
func WithAliases ¶
func WithAliases(names ...string) ConstructorOption
WithAliases registers the constructor result under additional named variants. The primary registration is by TYPE (unnamed), and aliases provide named access. This allows the service to be resolved both by type and by name.
Example:
// Register by type with named aliases
Provide(c, NewDatabaseManager, WithAliases("manager", "db-manager"))
// Can resolve by type (unnamed):
mgr1, _ := Inject[*DatabaseManager](c)
// Or by any alias name:
mgr2, _ := InjectNamed[*DatabaseManager](c, "manager")
mgr3, _ := InjectNamed[*DatabaseManager](c, "db-manager")
// mgr1 == mgr2 == mgr3 (same singleton instance)
Note: If you use WithName(), that becomes the primary name and aliases are additional. Using only WithAliases() keeps the service unnamed (type-based) as primary.
func WithEager ¶
func WithEager() ConstructorOption
WithEager causes the constructor to be invoked immediately after registration, rather than waiting for first use (lazy). This is useful for:
- Fail-fast behavior: catch construction errors at startup
- Services that need to initialize during app startup (servers, connections)
- Pre-warming caches
Example:
// Start database connection immediately, fail if can't connect Provide(c, NewDatabase, WithEager()) // Lazy (default): Wait until first use Provide(c, NewCache)
func WithName ¶
func WithName(name string) ConstructorOption
WithName gives the constructor result a name for disambiguation. Use this when you have multiple implementations of the same type.
Example:
Provide(c, NewPrimaryDB, WithName("primary"))
Provide(c, NewReplicaDB, WithName("replica"))
type DependencyGraph ¶
type DependencyGraph struct {
// contains filtered or unexported fields
}
DependencyGraph manages service dependencies.
func NewDependencyGraph ¶
func NewDependencyGraph() *DependencyGraph
NewDependencyGraph creates a new dependency graph.
func (*DependencyGraph) AddNode ¶
func (g *DependencyGraph) AddNode(name string, dependencies []string)
AddNode adds a node with its dependencies (string-based, backward compatible). Nodes are processed in the order they are added (FIFO) when no dependencies exist.
func (*DependencyGraph) AddNodeWithDeps ¶
func (g *DependencyGraph) AddNodeWithDeps(name string, deps []di.Dep)
AddNodeWithDeps adds a node with full Dep specs. This is the new API that supports lazy/optional dependencies.
func (*DependencyGraph) GetDependencies ¶
func (g *DependencyGraph) GetDependencies(name string) []string
GetDependencies returns the dependency names for a node.
func (*DependencyGraph) GetDeps ¶
func (g *DependencyGraph) GetDeps(name string) []di.Dep
GetDeps returns the full Dep specs for a node.
func (*DependencyGraph) GetEagerDependencies ¶
func (g *DependencyGraph) GetEagerDependencies(name string) []string
GetEagerDependencies returns only the eager (non-lazy) dependencies. These are the ones that must be resolved before the service can be created.
func (*DependencyGraph) HasNode ¶
func (g *DependencyGraph) HasNode(name string) bool
HasNode checks if a node exists in the graph.
func (*DependencyGraph) TopologicalSort ¶
func (g *DependencyGraph) TopologicalSort() ([]string, error)
TopologicalSort returns nodes in dependency order. Nodes without dependencies maintain their registration order (FIFO). Returns error if circular dependency detected.
func (*DependencyGraph) TopologicalSortEagerOnly ¶
func (g *DependencyGraph) TopologicalSortEagerOnly() ([]string, error)
TopologicalSortEagerOnly returns nodes sorted considering only eager dependencies. Lazy dependencies are excluded from the ordering since they're resolved on-demand.
type FuncMiddleware ¶
type FuncMiddleware struct {
BeforeResolveFunc func(ctx context.Context, name string) error
AfterResolveFunc func(ctx context.Context, name string, service any, err error) error
BeforeStartFunc func(ctx context.Context, name string) error
AfterStartFunc func(ctx context.Context, name string, err error) error
}
FuncMiddleware wraps functions as Middleware.
func (*FuncMiddleware) AfterResolve ¶
func (f *FuncMiddleware) AfterResolve(ctx context.Context, name string, service any, err error) error
AfterResolve implements Middleware.
func (*FuncMiddleware) AfterStart ¶
AfterStart implements Middleware.
func (*FuncMiddleware) BeforeResolve ¶
func (f *FuncMiddleware) BeforeResolve(ctx context.Context, name string) error
BeforeResolve implements Middleware.
func (*FuncMiddleware) BeforeStart ¶
func (f *FuncMiddleware) BeforeStart(ctx context.Context, name string) error
BeforeStart implements Middleware.
type In ¶
type In struct{}
In is a marker type that should be embedded in structs to indicate they are parameter objects. Fields of the struct will be treated as dependencies to inject. This follows the dig pattern for constructor injection.
Example:
type ServiceParams struct {
vessel.In
DB *Database
Logger *Logger `optional:"true"`
Cache *Cache `name:"redis"`
Handlers []http.Handler `group:"http"`
}
type Lazy ¶
type Lazy[T any] struct { // contains filtered or unexported fields }
Lazy wraps a dependency that is resolved on first access. This is useful for breaking circular dependencies or deferring resolution of expensive services until they're actually needed.
func (*Lazy[T]) Get ¶
Get resolves the dependency and returns it. The resolution happens only once; subsequent calls return the cached value.
func (*Lazy[T]) IsResolved ¶
IsResolved returns true if the dependency has been resolved.
type Middleware ¶
type Middleware interface {
// BeforeResolve is called before resolving a service.
// Return error to abort resolution.
BeforeResolve(ctx context.Context, name string) error
// AfterResolve is called after resolving a service.
// Called even if resolution failed (service and err may both be set).
AfterResolve(ctx context.Context, name string, service any, err error) error
// BeforeStart is called before starting a service.
// Return error to abort start.
BeforeStart(ctx context.Context, name string) error
// AfterStart is called after starting a service.
// Called even if start failed.
AfterStart(ctx context.Context, name string, err error) error
}
Middleware provides hooks for intercepting container operations. Middleware can be used for logging, metrics, security, testing, etc.
type OptionalLazy ¶
type OptionalLazy[T any] struct { // contains filtered or unexported fields }
OptionalLazy wraps an optional dependency that is resolved on first access. Returns nil without error if the dependency is not found.
func NewOptionalLazy ¶
func NewOptionalLazy[T any](container di.Container, name string) *OptionalLazy[T]
NewOptionalLazy creates a new optional lazy dependency wrapper.
func (*OptionalLazy[T]) Get ¶
func (l *OptionalLazy[T]) Get() (T, error)
Get resolves the dependency and returns it. Returns the zero value without error if the dependency is not found.
func (*OptionalLazy[T]) IsFound ¶
func (l *OptionalLazy[T]) IsFound() bool
IsFound returns true if the dependency was found (only valid after resolution).
func (*OptionalLazy[T]) IsResolved ¶
func (l *OptionalLazy[T]) IsResolved() bool
IsResolved returns true if the dependency has been resolved.
func (*OptionalLazy[T]) MustGet ¶
func (l *OptionalLazy[T]) MustGet() T
MustGet resolves the dependency and returns it, panicking on error. Returns the zero value if the dependency is not found (does not panic).
func (*OptionalLazy[T]) Name ¶
func (l *OptionalLazy[T]) Name() string
Name returns the name of the dependency.
type Out ¶
type Out struct{}
Out is a marker type that should be embedded in structs to indicate they are result objects. Each field of the struct will be registered as a separate service. This follows the dig pattern for multi-value returns.
Example:
type ServiceResult struct {
vessel.Out
UserService *UserService
ProductService *ProductService `name:"products"`
Handler http.Handler `group:"http"`
}
type Provider ¶
type Provider[T any] struct { // contains filtered or unexported fields }
Provider wraps a dependency that creates new instances on each access. This is useful for transient dependencies where a fresh instance is needed each time.
func NewProvider ¶
NewProvider creates a new provider for transient dependencies.
func (*Provider[T]) MustProvide ¶
func (p *Provider[T]) MustProvide() T
MustProvide resolves and returns a new instance, panicking on error.
type RegisterOption ¶
type RegisterOption = di.RegisterOption
RegisterOption is a configuration option for service registration.
type Scope ¶
Scope represents a lifetime scope for scoped services Typically used for HTTP requests or other bounded operations.
type ServiceInfo ¶
type ServiceInfo = di.ServiceInfo
ServiceInfo contains diagnostic information.
func FindByGroup ¶
func FindByGroup(c Vessel, group string) []ServiceInfo
FindByGroup returns all services in a specific group.
func FindByLifecycle ¶
func FindByLifecycle(c Vessel, lifecycle string) []ServiceInfo
FindByLifecycle returns all services with a specific lifecycle.
func FindNotStarted ¶
func FindNotStarted(c Vessel) []ServiceInfo
FindNotStarted returns all services that have not been started.
func FindStarted ¶
func FindStarted(c Vessel) []ServiceInfo
FindStarted returns all services that have been started.
func Query ¶
func Query(c Vessel, query ServiceQuery) []ServiceInfo
Query returns detailed information about services matching the query criteria. Returns a slice of ServiceInfo for all matching services.
Example:
// Find all singleton services in the "api" group
started := true
results := vessel.Query(c, vessel.ServiceQuery{
Lifecycle: "singleton",
Group: "api",
Started: &started,
})
type ServiceQuery ¶
type ServiceQuery struct {
// Lifecycle filters by service lifecycle (singleton, transient, scoped).
// Empty string matches all lifecycles.
Lifecycle string
// Group filters by service group.
// Empty string matches all groups.
Group string
// Metadata filters by service metadata key-value pairs.
// All specified metadata must match for a service to be included.
Metadata map[string]string
// Started filters by whether the service has been started.
// nil matches all services (started and not started).
Started *bool
}
ServiceQuery defines criteria for querying services.