Goldi: lazy dependency injection framework for go.
This library enables you to build your applications based on a dependency injection container.
It helps to make your code modular, flexible and ensures that you can reuse components easily.
If you are familiar with the Symfony dependency injection framework you should feel at home here.
The goldi API
Use go get
to get the goldi API:
$ go get github.com/fgrosse/goldi
No additional dependencies are required to use the library.
The full documentation is available at godoc.org. It is almost complete and includes a lot of examples on how to use goldi.
Usage
First you need to define the types you are going to use later
import (
"github.com/fgrosse/goldi"
"github.com/fgrosse/goldi/validation"
)
registry := goldi.NewTypeRegistry()
config := map[string]interface{}{
"some_parameter": "Hello World",
"timeout": 42.7,
}
container := goldi.NewContainer(registry, config)
container.RegisterType("logger", &SimpleLogger{})
container.RegisterType("api.geo.client", new(GeoClient), "http://example.com/geo:1234")
container.RegisterType("acme_corp.mailer", NewAwesomeMailer, "first argument", "%some_parameter%")
container.RegisterType("renderer", NewRenderer, "@logger")
container.Register("http_handler", goldi.NewFuncType(func(w http.ResponseWriter, r *http.Request) {
}))
validator := validation.NewContainerValidator()
validator.MustValidate(container)
logger := container.MustGet("logger").(LoggerInterface)
logger.DoStuff("...")
container.RegisterType("logger", NewNullLogger)
myLogger := NewNullLogger()
container.InjectInstance("logger", myLogger)
The types are build lazily. This means that the logger
will only be created when you ask the container for it the first time. Also all built types are singletons. This means that if you call container.Get("typeID")
two times you will always get the same instance of whatever typeID
stands for.
More detailed usage examples and a list of features will be available eventually.
The goldigen binary
If you are used to frameworks like Symfony you might want to define your types in an easy to maintain yaml file.
You can do this using goldigen.
Use go get
to install the goldigen binary:
$ go get github.com/fgrosse/goldi/goldigen
Goldigen depends on gopkg.in/yaml.v2 (LGPLv3) for the parsing of the yaml files and Kingpin (MIT licensed) for the command line flag parsing.
You then need to define your types like this:
types:
logger:
package: github.com/fgrosse/goldi-example/lib
type: SimpleLogger
my_fancy.client:
package: github.com/fgrosse/goldi-example/lib
type: Client
factory: NewDefaultClient
arguments:
- "%client_base_url%"
- "@logger"
time.clock:
package: github.com/fgrosse/goldi-example/lib/mytime
type: Clock
factory: NewSystemClock
http_handler:
package: github.com/fgrosse/servo/example
func: HandleHTTP
Now you have your type configuration file you can use goldigen like this:
$ goldigen --in config/types.yml --out lib/dependency_injection.go
This will generate the following output and write it to lib/dependency_injection.go
:
package lib
import (
"github.com/fgrosse/goldi"
"github.com/fgrosse/goldi-example/lib/mytime"
"github.com/fgrosse/servo/example"
)
func RegisterTypes(types goldi.TypeRegistry) {
types.RegisterAll(map[string]goldi.TypeFactory{
"http_handler": goldi.NewFuncType(example.HandleHTTP),
"logger": goldi.NewStructType(new(SimpleLogger)),
"my_fancy.client": goldi.NewType(NewDefaultClient, "%client_base_url%", "@logger"),
"time.clock": goldi.NewType(mytime.NewSystemClock),
})
}
As you might have noticed goldigen has created a go generate comment for you.
Next time you want to update dependency_injection.go
you can simply run go generate
.
Goldigen tries its best to determine the output files package by looking into your GOPATH
.
In certain situations this might not be enough so you can set a package explicitly using the --package
parameter.
For a full list of goldigens flags and parameters try:
$ goldigen --help
Now all you need to to is to create the di container as you would just using the goldi API and then somewhere in the bootstrapping of your application call.
RegisterTypes(registry)
If you have a serious error in your type registration (like returning more than one result from your type factory method)
goldi defers error handling by return an invalid type. You can check for invalid types with the ContainerValidator
or by using goldi.IsValid(TypeFactory)
directly.
Using the ContainerValidator
is always the preferred option since it will check for a wide variety of bad configurations
like undefined parameters or circular type dependencies.
Note that using goldigen is completely optional. If you do not like the idea of having an extra build step for your application just use goldis API directly.
License
Goldi is licensed under the the MIT license. Please see the LICENSE file for details.
Contributing
Any contributions are always welcome (use pull requests).
For each pull request make sure that you covered your changes and additions with ginkgo tests. If you are unsure how
to write those just drop me a message.
Please keep in mind that I might not always be able to respond immediately but I usually try to react within the week ☺.