Dependency Injection
Depedency Injection represent a powerful tool that injects dependencies into your application.
Inject over HTTP request
There are two main concept that you've to learn: Services and Modules.
Services
The first thing that we have to define is a Service. Services are components that produce something. The returned opject will be used by our service container to automatically resolve dependencies.
package service
import (
"fmt"
"github.com/RobyFerro/go-web/config"
"github.com/go-redis/redis/v7"
"github.com/labstack/gommon/log"
)
// ConnectRedis connect to Redis
func ConnectRedis() *redis.Client {
conf := config.GetRedis()
client := redis.NewClient(&redis.Options{
Addr: fmt.Sprintf("%s:%d", conf.Host, conf.Port),
Password: conf.Password,
DB: 1,
})
_, err := client.Ping().Result()
if err != nil {
log.Error(err)
}
return client
}
Modules
Modules are components that may contain multiple Services and must be implemented in the Controller definition.
package module
import (
"github.com/RobyFerro/go-web-framework/register"
"github.com/RobyFerro/go-web/service"
)
var MainModule = register.DIModule{
Name: "main",
Provides: []interface{}{
service.ConnectDB,
service.ConnectRedis,
service.ConnectElastic,
service.ConnectMongo,
},
}
This way we're saying that the dependencies declared in a specific controller has to be resolved within the attached modules.
package register
import (
foundation "github.com/RobyFerro/go-web-framework"
base_register "github.com/RobyFerro/go-web-framework/register"
"github.com/RobyFerro/go-web/app/console"
"github.com/RobyFerro/go-web/app/http/controller"
"github.com/RobyFerro/go-web/database/model"
"github.com/RobyFerro/go-web/module"
"github.com/RobyFerro/go-web/router"
)
// BaseEntities returns a struct that contains Go-Web base entities
func BaseEntities() foundation.BaseEntities {
return foundation.BaseEntities{
// ... other entities
Controllers: base_register.ControllerRegister{
base_register.ControllerRegisterItem{
Controller: &controller.UserController{}, // Controller definitions
Modules: []base_register.DIModule{
module.MainModule, // Module definitions
},
},
// other controllers ...
},
// other entities ...
}
}
Inject
Once you've defined your services you can use them in your application. You'll just need to define the type that is returned by one of our services as a parameter of:
- The
Run()
method present in a command - In methods implemented in our controller.
// Dependency injection in controller
package controller
import (
"github.com/RobyFerro/go-web-framework"
"github.com/RobyFerro/go-web/database/model"
"github.com/jinzhu/gorm"
)
type SampleController struct{
gwf.BaseController
}
// Main controller method
func (c *SampleController) Main(db *gorm.DB) {
// Il parametro `db *gorm.DB` è iniettato
// all'interno del controller tramite il service container
var user model.User
if err := db.Find(&user).Error;err != nil {
gwf.ProcessError(err)
}
}
Inject over CLI command
As with HTTP Injection, CLI commands can take advantage of the superpower of Dependency Injection.
Definition here is more simple. We've just to define our Service and register it in the Service
field located in the app/console/kernel.go
file.
package console
import (
"github.com/RobyFerro/go-web-framework/register"
"github.com/RobyFerro/go-web/service"
)
var (
// Commands is used to register all console commands.
Commands = register.CommandRegister{}
// Services will be used to create the Console Service Container.
// This container is created to allow dependency injection through console commands.
Services = register.ServiceRegister{
service.ConnectDB,
service.ConnectElastic,
service.ConnectMongo,
service.ConnectRedis,
// ... here is where we've to register out services
}
)
Similar to Controllers you can use Services in CLI command by declaring dependency ad parameter of the Run()
method.
package console
type Batman struct {
Signature string
Description string
Args string
}
// Command registration
func (c *Batman) Register() {
c.Signature = "command:signature"
c.Description = "Execute database seeder"
}
// Command business logic
func (c *Batman) Run(db *gorm.DB) {
// db *gorm.DB is injected
var user model.User
if err := db.Find(&user).Error;err != nil {
gwf.ProcessError(err)
}
}