di

package module
v0.14.0 Latest Latest
Warning

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

Go to latest
Published: Apr 29, 2022 License: MIT Imports: 11 Imported by: 0

README

di (Dependency Injection)

Go Reference CodeFactor Go Unit Tests CodeQL codecov

Installation

go get -u github.com/dtomasi/di

Usage example

See also /examples directory

package main

import (
	"fmt"
	"github.com/dtomasi/di"
	"log"
)

func BuildContainer() (*di.Container, error) {
	container := di.NewServiceContainer(
		// With given context
		// di.WithContext(...)

		// With a logger that implements logr interface
		// di.WithLogrImpl(...)

		// With a parameter provider. Something like viper or koanf ...
		// di.WithParameterProvider(...)
	)

	container.Register(
		// Services are registered using fmt.Stringer interface.
		// Using this interface enables DI to use strings as well as
		// integers or even pointers as map keys.
		di.NewServiceDef(di.StringRef("TestService1")).
			// A provider function
			Provider(func() (interface{}, error) { return nil, nil }).
			// Indicated "lazy" creation of services
			Opts(di.BuildOnFirstRequest()).
			Args(
				// Injects ctx.Context from di.Build
				di.ContextArg(),
				// Injects the whole DI Container
				di.ContainerArg(),
				// Injects another service
				di.ServiceArg(di.StringRef("OtherService")),
				// Inject multiple services by tag
				di.ServicesByTagsArg([]fmt.Stringer{di.StringRef("foo")}),
				// Injects a value using interface{}
				di.InterfaceArg(true),
				// Injects a parameter from registered provider
				// via Get(key string) (interface{}, error)
				di.ParamArg("foo.bar.baz"),
				// Inject Event Bus
				di.EventBusArg(),
			),
	)

	// Builds all services
	if err := container.Build(); err != nil {
		return nil, err
	}

	return container, nil
}

func main() {

	container, err := BuildContainer()
	if err != nil {
        panic(err)
	}

	testService := container.MustGet(di.StringRef("TestService1"))
}

Licence

Licence file

Documentation

Overview

Package di is a Dependency Injection library

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Container

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

Container is the actual service container struct.

func GetContainerFromContext added in v0.6.0

func GetContainerFromContext(ctx context.Context) (*Container, error)

GetContainerFromContext tries to get the container instance from given context as value.

func NewServiceContainer

func NewServiceContainer(opts ...Option) *Container

NewServiceContainer returns a new Container instance.

Example
package main

import (
	"context"
	"fmt"
	"github.com/dtomasi/di"
	"github.com/go-logr/logr/funcr"
	"os"
	"os/signal"
)

func main() {
	ctx, cancel := context.WithCancel(context.Background())

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt)

	defer func() {
		signal.Stop(ch)
		cancel()
	}()

	go func() {
		select {
		case <-ch:
			cancel()
		case <-ctx.Done():
		}
	}()

	// Create container
	container := di.NewServiceContainer(
		// Pass the context
		di.WithContext(ctx),
		// Add a debug logger
		// This can be any logger that implements logr.Logger interface
		di.WithLogrImpl(funcr.New(
			func(pfx, args string) { fmt.Println(pfx, args) },
			funcr.Options{ //nolint:exhaustivestruct
				LogCaller:    funcr.All,
				LogTimestamp: true,
				Verbosity:    6,
			}),
		),
		// Pass our parameter provider
		di.WithParameterProvider(&di.NoParameterProvider{}),
	)

	// Build the service container
	if err := container.Build(); err != nil {
		panic(err)
	}
}
Output:

func (*Container) Build

func (c *Container) Build() (err error)

Build will build the service container.

func (*Container) CancelContext added in v0.11.0

func (c *Container) CancelContext()

GetContext returns the context.

func (*Container) FindByTags added in v0.11.0

func (c *Container) FindByTags(tags []fmt.Stringer) ([]interface{}, error)

FindByTags finds all service instances with given tags and returns them as a slice.

func (*Container) Get

func (c *Container) Get(ref fmt.Stringer) (interface{}, error)

Get returns a requested service.

func (*Container) GetContext added in v0.7.0

func (c *Container) GetContext() context.Context

GetContext returns the context.

func (*Container) GetEventBus added in v0.6.0

func (c *Container) GetEventBus() *eventbus.EventBus

GetEventBus returns the eventbus instance. This is used to register to internal events that can be used as hooks.

func (*Container) MustGet

func (c *Container) MustGet(ref fmt.Stringer) interface{}

MustGet returns a service instance or panics on error.

func (*Container) Register

func (c *Container) Register(defs ...*ServiceDef)

Register lets you register a new ServiceDef to the container.

func (*Container) Set

func (c *Container) Set(ref fmt.Stringer, s interface{}) *Container

Set sets a service to container.

func (*Container) SetLogger added in v0.11.0

func (c *Container) SetLogger(l logr.Logger)

SetLogger allows to pass a logr after container initialization.

func (*Container) SetParameterProvider

func (c *Container) SetParameterProvider(pp ParameterProvider)

SetParameterProvider allows to set the parameter provider even after container initialization.

type ContextKey added in v0.6.0

type ContextKey int
const (
	ContextKeyContainer ContextKey = iota
)

type ErrorType added in v0.10.0

type ErrorType int
const (
	// Simple error codes.
	ContainerBuildError ErrorType = iota
	ServiceNotFoundError
	ServiceBuildError
	ProviderMissingError
	CallableNotAFuncError
	CallableToManyReturnValuesError
	CallableArgCountMismatchError
	CallableArgTypeMismatchError
	ParamProviderNotDefinedError
)

func (ErrorType) String added in v0.10.0

func (i ErrorType) String() string

type EventTopic added in v0.6.0

type EventTopic int
const (
	EventTopicDIReady EventTopic = iota // di:ready
)

func (EventTopic) String added in v0.6.0

func (i EventTopic) String() string

type NoParameterProvider added in v0.3.0

type NoParameterProvider struct{}

NoParameterProvider is a provider that is set by default.

func (*NoParameterProvider) Get added in v0.3.0

func (p *NoParameterProvider) Get(_ string) (interface{}, error)

func (*NoParameterProvider) Set added in v0.3.0

func (p *NoParameterProvider) Set(_ string, _ interface{}) error

type Option added in v0.3.0

type Option func(c *Container)

Option defines the option implementation.

func WithContext added in v0.3.0

func WithContext(ctx context.Context) Option

WithContext allows to provide a context to di container.

func WithEventBus added in v0.6.0

func WithEventBus(eb *eventbus.EventBus) Option

WithEventBus defines an eventbus.EventBus instance to use instead of an internal one.

func WithLogrImpl added in v0.3.0

func WithLogrImpl(l logr.Logger) Option

WithLogrImpl defines the logr.Logger implementation to use For details see: https://github.com/go-logr/logr#a-minimal-logging-api-for-go

func WithParameterProvider added in v0.3.0

func WithParameterProvider(pp ParameterProvider) Option

WithParameterProvider defines an option to set ParameterProvider interface.

type ParameterProvider

type ParameterProvider interface {
	// Get defines how a parameter is fetched from a provider.
	// We want to get an explicit error here to report it.
	Get(key string) (interface{}, error)
	// Set allows to set additional parameters.
	// If a value cannot be set we require an error to report it
	Set(key string, value interface{}) error
}

ParameterProvider defines the interface which is used in Container internally while building a service instance The interface is kept simple to achieve flexibility. It should be easy to use koanf or viper behind the scenes for managing parameters passed to the container. By default, di.Container is initialized with a map[string]interface{} provider.

type ServiceDef

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

ServiceDef is a definition of a service it describes how a service should be created and handled inside the service container.

func NewServiceDef

func NewServiceDef(ref fmt.Stringer) *ServiceDef

NewServiceDef creates a new service definition.

Example
package main

import (
	"github.com/dtomasi/di"
	"github.com/dtomasi/di/examples/simple/greeter"
)

func main() {
	def := di.NewServiceDef(
		// Internally di uses fmt.Stringer interface as map keys. This allows to use any type that can implement
		// this interface. You can use int´s or event pointers to a string ..
		di.StringRef("my_greeter_service_name"),
	).
		Provider(
			// Provider function that returns the service instance.
			// usually wrapped in a named function close to the service struct
			// Greeter Service borrowed from github.com/dtomasi/di/examples/simple/greeter
			greeter.NewGreeter,
		).
		Args(
			// This magic Arg injects the context provided with di container
			di.ContextArg(),
			// Interface Arg can be used for any value type. The passed value must match the target value type
			// in the provider function
			di.InterfaceArg("Hello, "),
			// NOTE: There are a bunch of other magic Args available. See documentation
		).
		// Adds a tag to the service definition. This allows to group services into logical units
		Tags(di.StringRef("greeter")).
		// Opt allows managing lifecycle of registered services within the container
		Opts(
			// This option defines that a service should not be created on Building the container.
			// It will be built when it is requested the first time via Get()
			di.BuildOnFirstRequest(),
			// This option defines that this service should always be newly created on request via Get()
			di.BuildAlwaysRebuild(),
		)

	// Getting the default (global) container instance for demo purpose
	container := di.NewServiceContainer()

	// Register the definition
	container.Register(def)

	// Build the service container (nothing is built in our case, because of the options above)
	if err := container.Build(); err != nil {
		panic(err)
	}

	// Get the service and greet John
	greeterService := container.MustGet(di.StringRef("my_greeter_service_name")).(*greeter.Greeter) // nolint
	greeterService.Greet("John")
}
Output:

func (*ServiceDef) Args

func (sd *ServiceDef) Args(args ...ServiceDefArg) *ServiceDef

Args accepts multiple constructor/provider function arguments.

func (*ServiceDef) Opts

func (sd *ServiceDef) Opts(opts ...ServiceOption) *ServiceDef

Opts allows to set some options for lifecycle management.

func (*ServiceDef) Provider

func (sd *ServiceDef) Provider(provider interface{}) *ServiceDef

Provider defines a function that returns the actual serve instance. This function can also accept arguments that are described using the Args function.

func (*ServiceDef) Tags added in v0.11.0

func (sd *ServiceDef) Tags(tags ...fmt.Stringer) *ServiceDef

AddTags allows to add multiple tags to a service definition.

type ServiceDefArg added in v0.13.0

type ServiceDefArg interface {
	Evaluate(*Container) (interface{}, error)
}

ServiceDefArg is the interface that arguments have to im.

func ContainerArg

func ContainerArg() ServiceDefArg

func ContextArg

func ContextArg() ServiceDefArg

func EventBusArg added in v0.11.0

func EventBusArg() ServiceDefArg

func InterfaceArg

func InterfaceArg(in interface{}) ServiceDefArg

InterfaceArg is a shortcut for an argument of type interface{}. This argument allows to pass any value that is provided to the service.

func ParamArg

func ParamArg(paramPath string) ServiceDefArg

func ServiceArg

func ServiceArg(ref fmt.Stringer) ServiceDefArg

func ServiceMethodCallArg added in v0.13.0

func ServiceMethodCallArg(serviceRef fmt.Stringer, methodName string, args ...ServiceDefArg) ServiceDefArg

func ServicesByTagsArg added in v0.11.0

func ServicesByTagsArg(tags []fmt.Stringer) ServiceDefArg

ServicesByTagsArg is a shortcut for a service argument.

type ServiceDefMap added in v0.5.0

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

func NewServiceDefMap added in v0.5.0

func NewServiceDefMap() *ServiceDefMap

func (*ServiceDefMap) Clear added in v0.5.0

func (rm *ServiceDefMap) Clear()

func (*ServiceDefMap) Count added in v0.5.0

func (rm *ServiceDefMap) Count() int

func (*ServiceDefMap) Delete added in v0.5.0

func (rm *ServiceDefMap) Delete(key fmt.Stringer)

func (*ServiceDefMap) Load added in v0.5.0

func (rm *ServiceDefMap) Load(key fmt.Stringer) (value *ServiceDef, ok bool)

func (*ServiceDefMap) Range added in v0.5.0

func (rm *ServiceDefMap) Range(f func(key fmt.Stringer, def *ServiceDef) error) error

func (*ServiceDefMap) Store added in v0.5.0

func (rm *ServiceDefMap) Store(key fmt.Stringer, value *ServiceDef)

type ServiceOption added in v0.2.0

type ServiceOption func(so *serviceOptions)

ServiceOption defines an option function.

func BuildAlwaysRebuild added in v0.2.0

func BuildAlwaysRebuild() ServiceOption

BuildAlwaysRebuild defines that a service should be rebuilt on each request.

func BuildOnFirstRequest

func BuildOnFirstRequest() ServiceOption

BuildOnFirstRequest option will not create an instance from on building the container. Instead, it will wait until the service is requested the first time.

type StringRef

type StringRef string

StringRef defines a service reference as string. As ServiceDef implements fmt.Stringer as an interface for referencing services.

func (StringRef) String

func (r StringRef) String() string

String implements fmt.Stringer interface method.

Directories

Path Synopsis
examples
internal

Jump to

Keyboard shortcuts

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