di

package
v0.6.3 Latest Latest
Warning

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

Go to latest
Published: Feb 4, 2025 License: Apache-2.0 Imports: 2 Imported by: 0

README

ajan/di

Overview

The di package provides a lightweight yet powerful dependency injection container for Go applications. It supports registration of concrete implementations, interface bindings, and dependency resolution through reflection. The package is designed to be simple to use while providing robust dependency management capabilities.

Features

  • Type-safe dependency injection
  • Interface-to-implementation binding
  • Container sealing to prevent runtime modifications
  • Dependency provider functions
  • Dependency listing
  • Support for dependency invocation

Basic Usage

import (
  ...
  "github.com/eser/ajan/di"
  ...
)

// Use the default container
container := di.Default

// Register dependencies
err := di.RegisterFn(
  container,
  configfx.RegisterDependencies,
  logfx.RegisterDependencies,
  httpfx.RegisterDependencies,
  // ... other dependencies
)
if err != nil {
  panic(err)
}

// Create and run the application
run := di.CreateInvoker(
  container,
  func(
    httpService httpfx.HttpService,
    // ... other dependencies
  ) error {
    err := httpService.Start()
    if err != nil {
      return err
    }

    return nil
  },
)

// Seal the container to prevent further modifications
di.Seal(container)

err = run()

API Reference

Registration
// Register a concrete implementation
di.Register(container, &MyService{})

// Register an implementation for an interface
di.RegisterFor[MyInterface](container, &MyImplementation{})

// Register using a provider function
di.RegisterFn(container, func() (MyInterface, error) {
    return &MyImplementation{}, nil
})
Resolution
// Get a dependency (with error checking)
service, ok := di.Get[MyService](container)
if !ok {
    // Handle missing dependency
}

// Get a dependency (panic if not found)
service := di.MustGet[MyService](container)
Dependency Listing
// Create a lister function for an interface
lister := di.CreateLister[MyInterface](container)
implementations := lister()

// Get implementations directly
implementations := di.DynamicList[MyInterface](container)
Invocation (preferred, w/ sealed container)
// Create an invoker function
invoker := di.CreateInvoker(container, func(
    service MyService,
    repo Repository,
) error {
    // Use dependencies
    return nil
})

// Execute the invoker
err := invoker()
Dynamic Invocation
err := di.DynamicInvoke(container, func(
    service MyService,
    repo Repository,
) error {
    // Use dependencies
    return nil
})

Example with Interfaces

// Define an interface
type Adder interface {
    Add(ctx context.Context, x, y int) (int, error)
}

// Create an implementation
type AdderImpl struct {
    di.Implements[Adder] // Mark as implementation
}

func (a AdderImpl) Add(ctx context.Context, x, y int) (int, error) {
    return x + y, nil
}

// Register and use
func main() {
    container := di.NewContainer()

    // Register implementation
    di.RegisterFor[Adder](container, AdderImpl{})

    // Use through dependency injection
    err := di.DynamicInvoke(container, func(adder Adder) error {
        result, err := adder.Add(context.Background(), 2, 3)
        if err != nil {
            return err
        }
        fmt.Printf("Result: %d\n", result)
        return nil
    })
}

Container Lifecycle

  1. Create or use the default container
  2. Register all dependencies
  3. Seal the container to prevent modifications
  4. Resolve and use dependencies

Best Practices

  • Register dependencies at application startup
  • Seal the container before using it
  • Use interfaces for better testability
  • Prefer RegisterFn for complex initialization
  • Use di.Implements[T] to mark interface implementations
  • Handle errors from RegisterFn and dependency resolution

Thread Safety

The container is not thread-safe during registration. Ensure all registrations are complete and the container is sealed before using it concurrently.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var Default = NewContainer() //nolint:gochecknoglobals

Functions

func CreateInvoker

func CreateInvoker(c *Container, fn any) func() error

func CreateLister

func CreateLister[I any](c *Container) func() []DependencyTarget

func DynamicInvoke

func DynamicInvoke(c *Container, fn any) error

func Get

func Get[I any](c *Container) (I, bool)

Get retrieves a registered implementation for the given interface.

func MustGet

func MustGet[I any](c *Container) I

MustGet retrieves a registered implementation or panics if not found.

func Register

func Register(c *Container, v any)

Register registers an implementation instance for a given interface.

func RegisterFn

func RegisterFn(c *Container, fns ...any) error

func RegisterFor

func RegisterFor[I any](c *Container, v I)

func Seal

func Seal(c *Container)

Types

type Container

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

Container defines the methods for dependency injection container.

func NewContainer

func NewContainer() *Container

NewContainer creates a new dependency injection container.

func (*Container) CreateInvoker

func (c *Container) CreateInvoker(fn any) func() error

func (*Container) CreateLister

func (c *Container) CreateLister(t reflect.Type) func() []DependencyTarget

func (*Container) DynamicInvoke

func (c *Container) DynamicInvoke(fn any) error

func (*Container) DynamicList

func (c *Container) DynamicList(t reflect.Type) []DependencyTarget

func (*Container) MustResolve

func (c *Container) MustResolve(t reflect.Type) DependencyTarget

func (*Container) Resolve

func (c *Container) Resolve(t reflect.Type) (DependencyTarget, bool)

func (*Container) Seal

func (c *Container) Seal()

func (*Container) SetValue

func (c *Container) SetValue(value any)

func (*Container) SetValueFor

func (c *Container) SetValueFor(interfaceType reflect.Type, value any)

func (*Container) SetValuesFromFunc

func (c *Container) SetValuesFromFunc(fns ...any) error

type DependencyTarget

type DependencyTarget struct {
	Value           any
	ReflectionValue reflect.Value
}

func DynamicList

func DynamicList[I any](c *Container) []DependencyTarget

type Implements

type Implements[I any] struct{}

Implements is a marker type to associate implementations with interfaces.

type Provider

type Provider func(args []any) any

Jump to

Keyboard shortcuts

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