Skip to content

Latest commit

 

History

History
174 lines (130 loc) · 6.28 KB

README.md

File metadata and controls

174 lines (130 loc) · 6.28 KB

Goldi

Build Status Coverage Status GoDoc license

Goldi: lazy dependency injection framework for go.

Note: This library is at the very early stages of its development.

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.

Usage

First you need to define the types you are going to use later

import "github.com/fgrosse/goldi"

// 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
container.RegisterType("logger", NewSimpleLogger)
container.RegisterType("acme_corp.mailer", NewAwesomeMailer, "first argument", "%some_parameter%")
container.RegisterType("renderer", NewRenderer, "@logger")

// once you are done registering all your types you should probably validate the container
validator := goldi.NewContainerValidator()
err := validator.Validate(container)
if err != nil {
    panic(err)
}

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

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

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 for the parsing of the yaml files and Kingpin 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: Logger                # Currently this does only serve a documentary purpose
        factory: NewSimpleLogger

    my_fancy.client:
        package: github.com/fgrosse/goldi-example/lib
        type: Client
        factory: NewDefaultClient
        arguments:
            - "%client_base_url%"   # As in the API you can use parameters here
            - "@logger"             # You can also reference other types 

    time.clock:
        package: github.com/fgrosse/goldi-example/lib/mytime
        type: Clock
        factory: NewSystemClock

Now you have your type configuration file you can use goldigen like this:

$ goldigen --in config/types.yml --out lib/dependency_injection.go --package lib

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"
)

// RegisterTypes registers all types that have been defined in the file "types.yml"
//
// DO NOT EDIT THIS FILE: it has been generated by goldigen v0.6.0.
// It is however good practice to put this file under version control.
// See https://github.com/fgrosse/goldi for what is going on here.
func RegisterTypes(types goldi.TypeRegistry) {
	types.RegisterType("logger", NewSimpleLogger)
	types.RegisterType("my_fancy.client", NewDefaultClient, "%client_base_url%", "@logger")
	types.RegisterType("time.clock", mytime.NewSystemClock)
}

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(container)

If you have a serious error in your type registration (like returning more than one result from your type factory method) goldi will panic. Additionally you should use the ContainerValidator to check for any 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.

Source Code Documentation

A generated documentation is available at godoc.org

Running the tests

Goldi uses the awesome ginkgo framework for its tests. If you want to run the tests you need to go get ginkgo and gomega You can execute the tests running:

$ go get github.com/onsi/ginkgo/ginkgo
$ go get github.com/onsi/gomega
$ ginkgo -r tests

If you prefer to use go test directly you can run the following from the repository root directory:

$ go test ./tests/...

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 ☺.