The container makes it easy to handle dependencies and utilise dependency injection on custom types, rather than hard-coding the dependencies into the type.
Binding to the Container
Gostalt uses sarulabs/di as a service container. To bind a new
service, add a new di.Def{} to the services slice in
app/services/app.go:
var services = []di.Def{
Name: "UserRepository",
Build: func(c di.Container) (interface{}, error) {
db := c.Get("database").(*sql.DB)
return &repository.User{
DB: db,
}, nil
}
}As you can see, a new service needs a Name and Build field.
The build field's value should be a function that accepts the
container as a parameter and returns an interface and an error.
In this example, we are resolving the "database" item out of the
container and using it as a value in the initialisation of a new
respository.User struct. This means that, should our database
details change, we don't need to change them in every area of our
codebase.
Note that, to retrieve an item from the container, you should use the
Getmethod to pass in the name of an item. Because this returns aninterface{}, it needs to be cast to the appropriate type—in the example above, we use*sql.DB.
For more complex services, it makes sense to create a dedicated
Service Provider, for example the LoggingServiceProvider or
the TLSServiceProvider. Service providers have two methods,
Register and Boot. The Register method is called on each
provider to create the container, and then the boot method is
called on each service provider.
You can create a service provider by declaring a new type:
type ExampleServiceProvider struct {
BaseServiceProvider
}As you can see above, the new service provider has a promoted
BaseServiceProvider field. This implements stub methods for
Register and Boot, meaning that we can omit them from our
Provider whilst still implementing the Provider interface.
Of course, you can override the Register and Boot methods
of the BaseServiceProvider by defining them on your new provider.
The naming is obvious, but you should only Register items into the container in the
Registermethod. If you attempt anything else in the Register method, the service may not yet have been created.