Documentation ¶
Index ¶
- Constants
- Variables
- func Get(i interface{}, name string) interface{}
- func HTTPMiddleware(h http.HandlerFunc, app Container, logFunc func(msg string)) http.HandlerFunc
- func NewBuildFuncForType(obj interface{}) (func(ctn Container) (interface{}, error), error)
- func NewIs(instances ...interface{}) []reflect.Type
- type Builder
- type Container
- func (ctn Container) Clean() error
- func (ctn Container) Definitions() map[string]Def
- func (ctn Container) DefinitionsForType(typ reflect.Type) []Def
- func (ctn Container) Delete() error
- func (ctn Container) DeleteWithSubContainers() error
- func (ctn Container) Fill(in interface{}, dst interface{}) error
- func (ctn Container) Get(in interface{}) interface{}
- func (ctn Container) IsClosed() bool
- func (ctn Container) NameIsDefined(name string) bool
- func (ctn Container) Parent() Container
- func (ctn Container) ParentContainer() (Container, error)
- func (ctn Container) ParentScopes() []string
- func (ctn Container) SafeGet(in interface{}) (interface{}, error)
- func (ctn Container) Scope() string
- func (ctn Container) Scopes() []string
- func (ctn Container) SubContainer() (Container, error)
- func (ctn Container) SubScopes() []string
- func (ctn Container) TypeIsDefined(typ reflect.Type) bool
- func (ctn Container) UnscopedFill(in interface{}, dst interface{}) error
- func (ctn Container) UnscopedGet(in interface{}) interface{}
- func (ctn Container) UnscopedSafeGet(in interface{}) (interface{}, error)
- type ContainerKey
- type Def
- func (d *Def) Index() int
- func (d *Def) SetBuild(build func(ctn Container) (interface{}, error)) *Def
- func (d *Def) SetClose(close func(obj interface{}) error) *Def
- func (d *Def) SetIs(instances ...interface{}) *Def
- func (d *Def) SetName(name string) *Def
- func (d *Def) SetScope(scope string) *Def
- func (d *Def) SetTags(tags ...Tag) *Def
- func (d *Def) SetUnshared(unshared bool) *Def
- type DefMap
- type EnhancedBuilder
- type ScopeList
- type Tag
Constants ¶
const App = "app"
App is the name of the application scope.
const Request = "request"
Request is the name of the request scope.
const SubRequest = "subrequest"
SubRequest is the name of the subrequest scope.
Variables ¶
var C = func(i interface{}) Container { if c, ok := i.(Container); ok { return c } r, ok := i.(*http.Request) if !ok { panic("could not get the container with C()") } c, ok := r.Context().Value(ContainerKey("di")).(Container) if !ok { panic("could not get the container from the given *http.Request") } return c }
C retrieves a Container from an interface. The function panics if the Container can not be retrieved.
The interface can be :
- a Container
- an *http.Request containing a Container in its context.Context for the ContainerKey("di") key.
The function can be changed to match the needs of your application.
Functions ¶
func HTTPMiddleware ¶
func HTTPMiddleware(h http.HandlerFunc, app Container, logFunc func(msg string)) http.HandlerFunc
HTTPMiddleware adds a container in the request context.
The container injected in each request, is a new sub-container of the app container given as parameter.
It can panic, so it should be used with another middleware to recover from the panic, and to log the error.
It uses logFunc, a function that can log an error. logFunc is used to log the errors during the container deletion.
func NewBuildFuncForType ¶ added in v2.5.0
NewBuildFuncForType returns a Build function that creates an instance of an object having the same type as the given obj. Only structures and pointers to structures are supported as input parameter. It will try to set the fields of the generated struct with objects from the container. Only definitions with a Is field including the type of the field can be used. If there is no definition for the field type, the field is left empty. If there are more than one definition for the field type, the one that was inserted last in the builder is used.
Types ¶
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
Builder can be used to create a Container. The Builder should be created with NewBuilder. Then you can add definitions with the Add method, and finally build the Container with the Build method.
Consider using the EnhancedBuilder that provides more features.
func NewBuilder ¶
NewBuilder is the only way to create a working Builder. It initializes a Builder with a list of scopes. The scopes are ordered from the most generic to the most specific. If no scope is provided, the default scopes are used: [App, Request, SubRequest] It can return an error if the scopes are not valid.
func (*Builder) Add ¶
Add adds one or more definitions in the Builder. It returns an error if a definition can not be added. If a definition with the same name has already been added, it will be replaced by the new one, as if the first one never existed.
func (*Builder) Build ¶
Build creates a Container in the most generic scope with all the definitions registered in the Builder.
func (*Builder) Definitions ¶
Definitions returns a map with the all the objects definitions registered with the Add method. The key of the map is the name of the Definition.
type Container ¶
type Container struct {
// contains filtered or unexported fields
}
Container represents a dependency injection container. To create a Container, you should use a Builder, an EnhancedBuilder or another Container.
A Container has a scope and may have a parent in a more generic scope and children in a more specific scope. Objects can be retrieved from the Container. If the requested object does not already exist in the Container, it is built thanks to the object definition.
func (Container) Clean ¶
Clean deletes the sub-container created by UnscopedSafeGet, UnscopedGet or UnscopedFill.
func (Container) Definitions ¶
Definitions returns the map of the available definitions ordered by name. These definitions represent all the objects that this Container can build.
func (Container) DefinitionsForType ¶ added in v2.5.0
DefinitionsForType returns the list of the definitions matching the given type. Types are declared in the Is field of a definition.
func (Container) Delete ¶
Delete works like DeleteWithSubContainers if the Container does not have any child. But if the Container has sub-containers, it will not be deleted right away. The deletion only occurs when all the sub-containers have been deleted manually. So you have to call Delete or DeleteWithSubContainers on all the sub-containers.
func (Container) DeleteWithSubContainers ¶
DeleteWithSubContainers takes all the objects saved in this Container and calls the Close function of their Definition on them. It will also call DeleteWithSubContainers on each child and remove its reference in the parent Container. After deletion, the Container can no longer be used. The sub-containers are deleted even if they are still used in other goroutines. It can cause errors. You may want to use the Delete method instead.
func (Container) Fill ¶
Fill is similar to SafeGet but it does not return the object. Instead it fills the provided object with the value returned by SafeGet. The provided object must be a pointer to the value returned by SafeGet. It uses reflection so it is slower than Get and SafeGet. But it can be convenient in some cases where performance is not a critical factor.
func (Container) Get ¶
func (ctn Container) Get(in interface{}) interface{}
Get retrieves an object from the Container. The object has to belong to the Container or one of its parents. If the object does not already exist, it is created and saved in the Container. If the object can not be created, it panics.
There are different ways to retrieve an object.
- From its name: ctn.Get("object-name")
- From its definition: ctn.Get(objectDef) or ctn.Get(objectDefPtr) - only with the EnhancedBuilder
- From its index: ctn.Get(objectDef.Index()) - only with the EnhancedBuilder
- From its type: ctn.Get(reflect.typeOf(MyObject{})) - only if objectDef.Is includes the given type In case there are more than one definition matching the given type, the chosen one is the last definition inserted in the builder.
func (Container) NameIsDefined ¶ added in v2.5.0
NameIsDefined returns true if there is a definition for the given name.
func (Container) Parent ¶
Parent returns the parent Container. It works like ParentContainer but without the error. This method was kept to have some kind of backward compatibility.
func (Container) ParentContainer ¶ added in v2.5.1
ParentContainer returns the parent Container. If the Container does not have a parent, it returns an error.
func (Container) ParentScopes ¶
ParentScopes returns the list of scopes that are more generic than the Container scope.
func (Container) SafeGet ¶
SafeGet retrieves an object from the Container. The object has to belong to the Container or one of its parents. If the object does not already exist, it is created and saved in the Container. If the object can not be created, it returns an error.
There are different ways to retrieve an object.
- From its name: ctn.SafeGet("object-name")
- From its definition: ctn.SafeGet(objectDef) or ctn.SafeGet(objectDefPtr) - only with the EnhancedBuilder
- From its index: ctn.SafeGet(objectDef.Index()) - only with the EnhancedBuilder
- From its type: ctn.SafeGet(reflect.typeOf(MyObject{})) - only if objectDef.Is includes the given type In case there are more than one definition matching the given type, the chosen one is the last definition inserted in the builder.
func (Container) SubContainer ¶
SubContainer creates a new Container in the next sub-scope that will have this Container as parent.
func (Container) SubScopes ¶
SubScopes returns the list of scopes that are more specific than the Container scope.
func (Container) TypeIsDefined ¶ added in v2.5.0
TypeIsDefined returns true if there is a definition for the given type. Types are declared in the Is field of a definition.
func (Container) UnscopedFill ¶
UnscopedFill is similar to UnscopedSafeGet but copies the object in dst instead of returning it.
func (Container) UnscopedGet ¶
func (ctn Container) UnscopedGet(in interface{}) interface{}
UnscopedGet is similar to UnscopedSafeGet but it does not return the error. Instead it panics.
func (Container) UnscopedSafeGet ¶
UnscopedSafeGet retrieves an object from the Container, like SafeGet. The difference is that the object can be retrieved even if it belongs to a more specific scope. To do so, UnscopedSafeGet creates a sub-container. When the created object is no longer needed, it is important to use the Clean method to delete this sub-container.
/!\ Do not use unscope functions inside a `Build` function. In this case, circular definitions are not detected. If you do this, you take the risk of having an infinite loop in your code when building an object.
type ContainerKey ¶
type ContainerKey string
ContainerKey is a type that can be used to store a container in the context.Context of an http.Request. By default, it is used in the C function and the HTTPMiddleware.
type Def ¶
type Def struct { // Build is the function that is used to create the object. Build func(ctn Container) (interface{}, error) // Close is the function that is used to clean the object when the container is deleted. // It can be nil if nothing needs to be done to close the object. Close func(obj interface{}) error // Name is the key that is used to retrieve the object from the container. Name string // Scope determines in which container the object is stored. // Typical scopes are "app" and "request". Scope string // They are singleton and the same instance will be returned each time "Get", "SafeGet" or "Fill" is called. // If you want to retrieve a new object every time, "Unshared" needs to be set to true. Unshared bool // Is allows to declare the type of the object generated by the Build function. // It is only declarative and no checks are done to ensure that this information is valid. // You can set multiple types, for example a structure and an interface implemented by the structure. // The Is field can be used to retrieve an object by its type instead of its name. // e.g.: ctn.Get(reflect.Type(MyStruct{})) // If multiple definitions have the same type, the one that was added last in the builder is used to retrieve the object. // The Is field is important if you are using NewBuildFuncForType. // It allows to create a Build function that creates an object whose fields are filled // depending on their type and the types of the definitions in the Container. Is []reflect.Type // Tags are not used inside this library. But they can be useful to sort your definitions. Tags []Tag // contains filtered or unexported fields }
Def contains information to build and close an object inside a Container.
func NewDef ¶ added in v2.5.0
NewDef creates a new *Def with only the Build function field set. You can also use the Def structure directly if it better fits your needs.
func NewDefFor ¶ added in v2.5.0
func NewDefFor(obj interface{}) *Def
NewDefFor creates a definition for an already built object. It is meant to replace the Set("object-name", objectInstance) of the basic Builder. If you want to add a name to the definition, you can use the setters. e.g.: NewDefFor(objectInstance).SetName("object-name")
func NewDefForType ¶ added in v2.5.0
func NewDefForType(obj interface{}) *Def
NewDefForType creates a definition that uses the result of NewBuildFuncForType(obj) as a Build function. The object generated by this definition will have the same type as the obj parameter. obj can only be a struct or a pointer to a struct. Other types are not supported. The fields of the generated object are filled with objects from the container depending on their types and the Is field of the definitions in the Container.
The object will be generated using reflection. That implies that it is slower compared to a manually written function. But if you just use this for shared definitions in the main scope, it should not be a problem as the objects are only built once.
func (*Def) Index ¶ added in v2.5.0
Index returns the index of the definition in its Container. If the definition is not bound to a Container, it returns -1.
func (*Def) SetIs ¶ added in v2.5.0
SetIs is the setter for the Is field. But the input parameters are not reflect.Type, but object instances. It uses NewIs to convert instances to []reflect.Type.
func (*Def) SetUnshared ¶ added in v2.5.0
SetUnshared is the setter for the Unshared field.
type EnhancedBuilder ¶ added in v2.5.0
type EnhancedBuilder struct {
// contains filtered or unexported fields
}
EnhancedBuilder can be used to create a Container. The EnhancedBuilder should be created with NewEnhancedBuilder. Then you can add definitions with the Add method. Once all the definitions have been added to the builder, you can generate the Container with the Build method.
It works the same way as the basic Builder. But the definitions given to the Add method are pointers. The definitions are updated when the Build method is called. That allows to retrieve objects by their definitions which is faster than retrieving them by name.
func NewEnhancedBuilder ¶ added in v2.5.0
func NewEnhancedBuilder(scopes ...string) (*EnhancedBuilder, error)
NewEnhancedBuilder is the only way to create a working EnhancedBuilder. It initializes an EnhancedBuilder with a list of scopes. The scopes are ordered from the most generic to the most specific. If no scope is provided, the default scopes are used: [App, Request, SubRequest] It can return an error if the scopes are not valid.
func (*EnhancedBuilder) Add ¶ added in v2.5.0
func (b *EnhancedBuilder) Add(def *Def) error
Add adds one definition to the Builder. It returns an error if the definition can not be added.
The name must be unique. If a definition with the same name has already been added, it will be replaced by the new one, as if the first one never was added. If an empty name is provided, a name starting with "_di_generated_" is generated. You can not add a definition with a name starting with "_di_generated_" as it is reserved for auto-genrated ones. Providing a name is recommended as it makes errors much easier to understand.
The input definition is a pointer. It will be updated when the container is generated with the Build method. It binds the definition to the generated Container. That allows to build an object not only from its name but also from its definition which happens to be faster.
func (*EnhancedBuilder) Build ¶ added in v2.5.0
func (b *EnhancedBuilder) Build() (Container, error)
Build creates a Container in the most generic scope with all the definitions registered in the builder.
The definition provided in the Add method are updated to match their state when they were added to the builder.
A definition can only belong to one container. That means you can only call Build once.
func (*EnhancedBuilder) Definitions ¶ added in v2.5.0
func (b *EnhancedBuilder) Definitions() DefMap
Definitions returns a map with the all objects definitions registered at this point. The key of the map is the name of the definition.
func (*EnhancedBuilder) NameIsDefined ¶ added in v2.5.0
func (b *EnhancedBuilder) NameIsDefined(name string) bool
NameIsDefined returns true if there is a definition registered with the given name.
func (*EnhancedBuilder) Scopes ¶ added in v2.5.0
func (b *EnhancedBuilder) Scopes() ScopeList
Scopes returns the list of available scopes.