di is a dependency injection framework for Go. di supplies several dependency lifetime caching policies, provides dependency aware http handlers compatible with net/http, and provides a way to clean up dependencies instantiated during an http request.
di only resolves dependencies which are interfaces, the resolver itself, http.ResponseWriter, and *http.Request.
- Singleton
- only one instance created throughout the life of the resolver
- PerDependency
- a new instance created for each dependency encountered, every time Resolve() is called
- PerHttpRequest
- a new instance is created for each HTTP request, and reused for the duration of the request. The dependency has an option to implement an interface which will be called back once the request is over
- PerResolve
- a new instance is created for each call of Resolve(), and then re-used throughout that call. Subsequent calls to Resolve() create new instances
dependencies := []*di.Def{
{SomeConstructor, di.PerHttpRequest},
// etc...
}
httpDefs := []*di.HttpDef{
// the http.ResponseWriter and *http.Request values are available as dependencies,
// the resolver is also available as a dependency as an di.IResolver
// SomeHandler => func(dep1 Dep1, dep2 Dep2, etc)
{SomeHandler, "/some/pattern"},
// etc...
}
resolver, err := di.NewResolver(errHandler, dependencies)
// if err
err = resolver.SetDefaultServeMux(httpDefs)
// if err
log.Fatal(http.ListenAndServe(":8080", nil))
A more complete example is available here
di can resolve a dependency directly if known. The dependency instance follows the lifecycle caching rules of the resolver
var someDependency Dependency
resolveErr := resolver.Resolve(&someDependency)
di can curry the parameters of funcs with dependencies known to a resolver, returning a new func that only contains parameters the caller would like to supply themselves.
func normalFunc(name string, dep Dep) (int, string) {
// DoThing(name) == 5
return dep.DoThing(name), name + "!"
}
ifunc, resolveErr := resolver.Curry(normalFunc)
// if resolveErr
value, msg := ifunc.(func (string)(int, string))("hello")
// 5, "hello!"
resolveErr := resolver.Invoke(func (dep Dep){
// do()
})
If the func returns an error, and no error is encountered while resolving the dependencies, that error is returned instead
resolveErr := resolver.Invoke(func (dep Dep) error {
innerErr := dep1.Do()
return innerErr
})
// resolveErr.Err == innerErr