goldi: github.com/fgrosse/goldi Index | Examples | Files | Directories

package goldi

import "github.com/fgrosse/goldi"

Package goldi implements a lazy dependency injection framework for go. Goldi is MIT-Licensed

Example_ prevents godoc from printing the whole content of this file as example

Code:


          
        

Code:

// create a new container when your application loads
registry := goldi.NewTypeRegistry()
config := map[string]interface{}{
    "some_parameter": "Hello World",
    "timeout":        42.7,
}
container := goldi.NewContainer(registry, config)

// now define the types you want to build using the di container
// you can use simple structs
container.RegisterType("logger", &SimpleLogger{})
container.RegisterType("api.geo.client", new(GeoClient), "http://example.com/geo:1234")

// you can also use factory functions and parameters
container.RegisterType("acme_corp.mailer", NewAwesomeMailer, "first argument", "%some_parameter%")

// dynamic or static parameters and references to other services can be used as arguments
container.RegisterType("renderer", NewRenderer, "@logger")

// closures and functions are also possible
container.Register("http_handler", goldi.NewFuncType(func(w http.ResponseWriter, r *http.Request) {
    // do amazing stuff
}))

// once you are done registering all your types you should probably validate the container
validator := validation.NewContainerValidator()
validator.MustValidate(container) // will panic, use validator.Validate to get the error

// whoever has access to the container can request these types now
logger := container.MustGet("logger").(LoggerInterface)
logger.DoStuff("...")

// in the tests you might want to exchange the registered types with mocks or other implementations
container.RegisterType("logger", NewNullLogger)

// if you already have an instance you want to be used you can inject it directly
myLogger := NewNullLogger()
container.InjectInstance("logger", myLogger)

Index

Examples

Package Files

alias_type.go configured_type.go container.go doc.go errors.go func_reference_type.go func_type.go instance_type.go invalid_type.go parameter_resolver.go proxy_type.go string_set.go struct_type.go type.go type_configurator.go type_factory.go type_id.go type_registry.go

func IsParameter Uses

func IsParameter(p string) bool

IsParameter returns whether the given type ID represents a parameter. A goldi parameter is recognized by the leading and trailing percent sign Example: %foobar%

func IsParameterOrTypeReference Uses

func IsParameterOrTypeReference(p string) bool

IsParameterOrTypeReference is a utility function that returns whether the given string represents a parameter or a reference to a type. See IsParameter and IsTypeReference for further details

func IsTypeReference Uses

func IsTypeReference(p string) bool

IsTypeReference returns whether the given string represents a reference to a type. A goldi type reference is recognized by the leading @ sign. Example: @foobar

func IsValid Uses

func IsValid(t TypeFactory) bool

IsValid checks if a given type factory is valid. This function can be used to check the result of functions like NewType

type Container Uses

type Container struct {
    TypeRegistry
    Config   map[string]interface{}
    Resolver *ParameterResolver
    // contains filtered or unexported fields
}

Container is the dependency injection container that can be used by your application to define and get types.

Basically this is just a TypeRegistry with access to the application configuration and the knowledge of how to build individual services. Additionally this implements the laziness of the DI using a simple in memory type cache

You must use goldi.NewContainer to get a initialized instance of a Container!

Code:

registry := goldi.NewTypeRegistry()
config := map[string]interface{}{}
container := goldi.NewContainer(registry, config)

container.Register("logger", goldi.NewType(NewNullLogger))

l := container.MustGet("logger")
fmt.Printf("%T", l)

Output:

*goldi_test.NullLogger

func NewContainer Uses

func NewContainer(registry TypeRegistry, config map[string]interface{}) *Container

NewContainer creates a new container instance using the provided arguments

func (*Container) Get Uses

func (c *Container) Get(typeID string) (interface{}, error)

Get retrieves a previously defined type or an error. If the requested typeID has not been registered before or can not be generated Get will return an error.

For your dependency injection to work properly it is important that you do only try to assert interface types when you use Get(..). Otherwise it might be impossible to assert the correct type when you change the underlying type implementations. Also make sure your application is properly tested and defers some panic handling in case you forgot to define a service.

See also Container.MustGet

Code:

registry := goldi.NewTypeRegistry()
config := map[string]interface{}{}
container := goldi.NewContainer(registry, config)

container.Register("logger", goldi.NewType(NewNullLogger))

l, err := container.Get("logger")
if err != nil {
    fmt.Println(err.Error())
    return
}

// do stuff with the logger. usually you need a type assertion
fmt.Printf("%T", l.(*NullLogger))

Output:

*goldi_test.NullLogger

func (*Container) MustGet Uses

func (c *Container) MustGet(typeID string) interface{}

MustGet behaves exactly like Get but will panic instead of returning an error Since MustGet can only return interface{} you need to add a type assertion after the call:

container.MustGet("logger").(LoggerInterface)

type ParameterResolver Uses

type ParameterResolver struct {
    Container *Container
}

The ParameterResolver is used by type factories to resolve the values of the dynamic factory arguments (parameters and other type references).

func NewParameterResolver Uses

func NewParameterResolver(container *Container) *ParameterResolver

NewParameterResolver creates a new ParameterResolver and initializes it with the given Container. The container is used when resolving parameters and the type references.

func (*ParameterResolver) Resolve Uses

func (r *ParameterResolver) Resolve(parameter reflect.Value, expectedType reflect.Type) (reflect.Value, error)

Resolve takes a parameter and resolves any references to configuration parameter values or type references. If the type of `parameter` is not a parameter or type reference it is returned as is. Parameters must always have the form `%my.beautiful.param%. Type references must have the form `@my_type.bla`. It is also legal to request an optional type using the syntax `@?my_optional_type`. If this type is not registered Resolve will not return an error but instead give you the null value of the expected type.

type StringSet Uses

type StringSet map[string]struct{}

A StringSet represents a set of strings.

func (StringSet) Contains Uses

func (s StringSet) Contains(value string) bool

Contains returns true if the given value is contained in this string set.

func (StringSet) Set Uses

func (s StringSet) Set(value string)

Set adds a value to the set.

type TypeConfigurator Uses

type TypeConfigurator struct {
    ConfiguratorTypeID string
    MethodName         string
}

The TypeConfigurator is used to configure a type after its instantiation. You can specify a function in another type that is known to the container. The type instance is passed to the configurator type, allowing the configurator to do whatever it needs to configure the type after its creation.

A TypeConfigurator can be used, for example, when you have a type that requires complex setup based on configuration settings coming from different sources. Using an external configurator, you can decouple the setup logic from the business logic of the corresponding type to keep it DRY and easy to maintain. Also this way its easy to exchange setup logic at run time for example on different environments.

Another interesting use case is when you have multiple objects that share a common configuration or that should be configured in a similar way at runtime.

func NewTypeConfigurator Uses

func NewTypeConfigurator(configuratorTypeID, methodName string) *TypeConfigurator

NewTypeConfigurator creates a new TypeConfigurator

func (*TypeConfigurator) Configure Uses

func (c *TypeConfigurator) Configure(thing interface{}, container *Container) error

Configure will get the configurator type and ass `thing` its configuration function. The method returns an error if thing is nil, the configurator type is not defined or the configurators function does not exist.

type TypeFactory Uses

type TypeFactory interface {

    // Arguments returns all arguments that are used to generate the type.
    // This enables the container validator to check if all required parameters exist
    // and if there are circular type dependencies.
    Arguments() []interface{}

    // Generate will instantiate a new instance of the according type or return an error.
    Generate(parameterResolver *ParameterResolver) (interface{}, error)
}

A TypeFactory is used to instantiate a certain type.

func NewAliasType Uses

func NewAliasType(typeID string) TypeFactory

NewAliasType create a new TypeFactory which just serves as alias to the given type ID.

A call to an alias type will retrieve the aliased type as if it was requested via container.Get(typeID) This method will always return a valid type and works bot for regular type references (without leading @) and references to type functions.

Goldigen yaml syntax example:

type_that_is_aliased:
    alias: "@some_type"  // container.Get("type_that_is_aliased") will now return "some_type" instead

Goldigen yaml syntax example with function reference:

func_type_that_is_aliased:
    alias: "@some_type::DoStuff"

Code:

container := goldi.NewContainer(goldi.NewTypeRegistry(), map[string]interface{}{})

container.Register("logger", goldi.NewStructType(SimpleLogger{}))
container.Register("default_logger", goldi.NewAliasType("logger"))
container.Register("logging_func", goldi.NewAliasType("logger::DoStuff"))

fmt.Printf("logger:         %T\n", container.MustGet("logger"))
fmt.Printf("default_logger: %T\n", container.MustGet("default_logger"))
fmt.Printf("logging_func:   %T\n", container.MustGet("logging_func"))

Output:

logger:         *goldi_test.SimpleLogger
default_logger: *goldi_test.SimpleLogger
logging_func:   func(string) string

ExampleNewAliasType_ prevents godoc from printing the whole content of this file as example

Code:


          
        

func NewConfiguredType Uses

func NewConfiguredType(embeddedType TypeFactory, configuratorTypeID, configuratorMethod string) TypeFactory

NewConfiguredType creates a new TypeFactory that decorates a given TypeFactory. The returned configurator will use the decorated type factory first to create a type and then use the resolve the configurator by the given type ID and call the configured method with the instance.

Internally the goldi.TypeConfigurator is used.

The method removes any leading or trailing whitespace from configurator type ID and method. NewConfiguredType will return an invalid type when embeddedType is nil or the trimmed configurator typeID or method is empty.

Goldigen yaml syntax example:

my_type:
    package: github.com/fgrosse/foobar
    type:    MyType
    configurator: [ "@my_configurator", Configure ]

Code:

container := goldi.NewContainer(goldi.NewTypeRegistry(), map[string]interface{}{})

// this example configurator accepts a Foo type and will set its Value field to the given value
configurator := &MyConfigurator{ConfiguredValue: "success!"}

// register the configurator under a type ID
container.Register("configurator_type", goldi.NewInstanceType(configurator))

// create the type that should be configured
embeddedType := goldi.NewStructType(Foo{})
container.Register("foo", goldi.NewConfiguredType(embeddedType, "configurator_type", "Configure"))

fmt.Println(container.MustGet("foo").(*Foo).Value)

Output:

success!

ExampleNewConfiguredType_ prevents godoc from printing the whole content of this file as example

Code:


          
        

func NewFuncReferenceType Uses

func NewFuncReferenceType(typeID, functionName string) TypeFactory

NewFuncReferenceType returns a TypeFactory that returns a method of another type as method value (function).

Goldigen yaml syntax example:

my_func_type:
    func: "@some_type::FancyAction"

Code:

container := goldi.NewContainer(goldi.NewTypeRegistry(), map[string]interface{}{})

logger := new(SimpleLogger)
container.Register("logger", goldi.NewInstanceType(logger))
container.Register("log_func", goldi.NewFuncReferenceType("logger", "DoStuff"))

f := container.MustGet("log_func").(func(string) string)
fmt.Println(f("Hello World")) // executes logger.DoStuff

Output:

Hello World

ExampleNewFuncReferenceType_ prevents godoc from printing the whole content of this file as example

Code:


          
        

func NewFuncType Uses

func NewFuncType(function interface{}) TypeFactory

NewFuncType creates a new TypeFactory that will return a method value

Goldigen yaml syntax example:

my_func_type:
    package: github.com/fgrosse/foobar
    func:    DoStuff

Code:

container := goldi.NewContainer(goldi.NewTypeRegistry(), map[string]interface{}{})

// define the type
container.Register("my_func", goldi.NewFuncType(func(w http.ResponseWriter, r *http.Request) {
    if r.URL.Path == "test" {
        w.WriteHeader(http.StatusAccepted)
    }
}))

// generate it
result, err := container.Get("my_func")
if err != nil {
    return
}

// call it
f := result.(func(name string, age int) (bool, error))
ok, err := f("foo", 42)
if ok != true || err != nil {
    panic("!!!")
}

ExampleNewFuncType_ prevents godoc from printing the whole content of this file as example

Code:


          
        

func NewInstanceType Uses

func NewInstanceType(instance interface{}) TypeFactory

NewInstanceType creates a new TypeFactory which will return the given instance on each call to Generate. It will return an invalid type factory if the given instance is nil

You can not generate this type using goldigen

Code:

container := goldi.NewContainer(goldi.NewTypeRegistry(), map[string]interface{}{})

myInstance := new(SimpleLogger)
myInstance.Name = "Foobar" // you can configure the instance in your code

// now register this instance as a type
container.Register("logger", goldi.NewInstanceType(myInstance))

// each reference to the "logger" type will now be resolved to that instance
fmt.Println(container.MustGet("logger").(*SimpleLogger).Name)

Output:

Foobar

ExampleNewInstanceType_ prevents godoc from printing the whole content of this file as example

Code:


          
        

func NewProxyType Uses

func NewProxyType(typeID, functionName string, args ...interface{}) TypeFactory

NewProxyType returns a TypeFactory that uses a function of another type to generate a result.

Goldigen yaml syntax example:

logger:
    factory: "@logger_provider::GetLogger"
    args:    [ "My Logger" ]

ExampleNewProxyType_ prevents godoc from printing the whole content of this file as example

Code:


          
        

Let's assume that we have a LoggerProvider type that produces configured instances of a Logger each time we call LoggerProvider.GetLogger(loggerName string).

The example shows how to register a `logger` as proxy for a specific call to this LoggerProvider.

Code:

container := goldi.NewContainer(goldi.NewTypeRegistry(), map[string]interface{}{})

// register some type as always
container.Register("logger_provider", goldi.NewStructType(LoggerProvider{}))

// register a proxy type that references the method of previously defined type and append call arguments if any
container.Register("logger", goldi.NewProxyType("logger_provider", "GetLogger", "My logger"))

l := container.MustGet("logger").(*SimpleLogger)
fmt.Printf("%s: %T", l.Name, l)

Output:

My logger: *goldi_test.SimpleLogger

func NewStructType Uses

func NewStructType(structT interface{}, structParameters ...interface{}) TypeFactory

NewStructType creates a TypeFactory that can be used to create a new instance of some struct type.

This function will return an invalid type if:

- structT is no struct or pointer to a struct,
- the number of given structParameters exceed the number of field of structT
- the structParameters types do not match the fields of structT

Goldigen yaml syntax example:

logger:
    package: github.com/fgrosse/foobar
    type:    MyType

ExampleNewStructType_ prevents godoc from printing the whole content of this file as example

Code:


          
        

Code:

container := goldi.NewContainer(goldi.NewTypeRegistry(), map[string]interface{}{})

// all of the following types are semantically identical
container.Register("foo_1", goldi.NewStructType(Foo{}))
container.Register("foo_2", goldi.NewStructType(&Foo{}))
container.Register("foo_3", goldi.NewStructType(new(Foo)))

// each reference to the "logger" type will now be resolved to that instance
fmt.Printf("foo_1: %T\n", container.MustGet("foo_1"))
fmt.Printf("foo_2: %T\n", container.MustGet("foo_2"))
fmt.Printf("foo_3: %T\n", container.MustGet("foo_3"))

Output:

foo_1: *goldi_test.Foo
foo_2: *goldi_test.Foo
foo_3: *goldi_test.Foo

func NewType Uses

func NewType(factoryFunction interface{}, factoryParameters ...interface{}) TypeFactory

NewType creates a new TypeFactory.

This function will return an invalid type if:

- the factoryFunction is nil or no function,
- the factoryFunction returns zero or more than one parameter
- the factoryFunctions return parameter is no pointer, interface  or function type.
- the number of given factoryParameters does not match the number of arguments of the factoryFunction

Goldigen yaml syntax example:

my_type:
    package: github.com/fgrosse/foobar
    factory: NewType
    args:
        - "Hello World"
        - true

ExampleNewType_ prevents godoc from printing the whole content of this file as example

Code:


          
        

Code:

container := goldi.NewContainer(goldi.NewTypeRegistry(), map[string]interface{}{})

// register the type using the factory function NewMockTypeWithArgs and pass two arguments
container.Register("my_type", goldi.NewType(NewMockTypeWithArgs, "Hello World", true))

t := container.MustGet("my_type").(*MockType)
fmt.Printf("%#v", t)

Output:

&goldi_test.MockType{StringParameter:"Hello World", BoolParameter:true}

type TypeID Uses

type TypeID struct {
    ID, Raw             string
    FuncReferenceMethod string
    IsOptional          bool
    IsFuncReference     bool
}

TypeID represents a parsed type identifier and associated meta data.

func NewTypeID Uses

func NewTypeID(s string) *TypeID

NewTypeID creates a new TypeId. Trying to create a type ID from an empty string will panic

func (*TypeID) String Uses

func (t *TypeID) String() string

String implements the fmt.Stringer interface by returning the raw representation of this type ID.

type TypeReferenceError Uses

type TypeReferenceError struct {
    TypeID       string
    TypeInstance interface{}
    // contains filtered or unexported fields
}

A TypeReferenceError occurs if you tried to inject a type that does not match the function declaration of the corresponding method.

type TypeRegistry Uses

type TypeRegistry map[string]TypeFactory

The TypeRegistry is effectively a map of typeID strings to TypeFactory

func NewTypeRegistry Uses

func NewTypeRegistry() TypeRegistry

NewTypeRegistry creates a new empty TypeRegistry

func (TypeRegistry) InjectInstance Uses

func (r TypeRegistry) InjectInstance(typeID string, instance interface{})

InjectInstance enables you to inject type instances. If instance is nil an error is returned

func (TypeRegistry) Register Uses

func (r TypeRegistry) Register(typeID string, typeDef TypeFactory)

Register saves a type under the given symbolic typeID so it can be retrieved later. It is perfectly legal to call Register multiple times with the same typeID. In this case you overwrite existing type definitions with new once

func (TypeRegistry) RegisterAll Uses

func (r TypeRegistry) RegisterAll(factories map[string]TypeFactory)

RegisterAll will register all given type factories under the mapped type ID It uses TypeRegistry.Register internally

func (TypeRegistry) RegisterType Uses

func (r TypeRegistry) RegisterType(typeID string, factory interface{}, arguments ...interface{})

RegisterType is convenience method for TypeRegistry.Register It tries to create the correct TypeFactory and passes this to TypeRegistry.Register This function panics if the given generator function and arguments can not be used to create a new type factory.

type UnknownTypeReferenceError Uses

type UnknownTypeReferenceError struct {
    TypeID string
    // contains filtered or unexported fields
}

The UnknownTypeReferenceError occurs if you try to get a type by an unknown type id (type has not been registered).

Directories

PathSynopsis
goldigenThe goldigen binary See https://github.com/fgrosse/goldi#the-goldigen-binary
validationPackage validation provides simple validation of goldi containers

Package goldi imports 5 packages (graph) and is imported by 9 packages. Updated 2018-12-21. Refresh now. Tools for package owners.