Wire
Wire is a powerful code generation tool
designed to automate the process of connecting components through dependency injection
in Golang. By representing dependencies as function parameters, Wire encourages explicit initialization over the use of global variables
. Unlike some other dependency injection tools for Go, such as dig, Wire operates without relying on runtime state or reflection
. This characteristic not only ensures efficient code execution but also makes code written for Wire compatible with manual initialization
.
Key Features
Code Generation
Wire operates as a code generator, eliminating the need for calls to a runtime library
. This approach facilitates introspection of initialization and ensures accurate cross-references.
Providers and Injectors
Wire introduces two core concepts - providers
and injectors
. Providers are functions that produce values, while injectors call providers in dependency order
. This enables clean and organized initialization of components.
Provider Sets
Providers can be grouped into provider sets, a convenient way to manage and use multiple providers together when necessary
.
Generating code
Build Constrains
To generate the injector, add the build constraint //+build wireinject
to your code. A build constraint, also known as a build tag
, is a condition under which a file should be included in the package. Build constraints are given by a line comment that begins.
To generate code, run Wire in the package directory with the wire.go
present. The generated implementation of the injector will be saved in a file named wire_gen.go
.
Example
//go:build wireinject
// +build wireinject
// The build tag makes sure the stub is not built in the final build.
package main
import (
"database/sql"
"github.com/RomeroGabriel/dependency-inversion/product"
"github.com/RomeroGabriel/dependency-inversion/user"
"github.com/google/wire"
)
// Provider: a function that can produce a value.
// Sets are useful if several providers will frequently be used together.
var setRepositoryDependency = wire.NewSet(
product.NewProductRepository,
wire.Bind(new(product.ProductRepositoryInterface), new(*product.ProductRepository)),
user.NewUserRepository,
wire.Bind(new(user.UserRepositoryInterface), new(*user.UserRepository)),
)
func NewProductUseCase(db *sql.DB) *product.ProductUseCase {
wire.Build(
setRepositoryDependency,
product.NewProductUseCase,
)
return &product.ProductUseCase{}
}
func NewUserUseCase(db *sql.DB) *user.UserUseCase {
wire.Build(
setRepositoryDependency,
user.NewUserUseCase,
)
return &user.UserUseCase{}
}
// Code generated by Wire. DO NOT EDIT.
//go:generate go run github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
package main
import (
"database/sql"
"github.com/RomeroGabriel/dependency-inversion/product"
"github.com/RomeroGabriel/dependency-inversion/user"
"github.com/google/wire"
)
import (
_ "github.com/mattn/go-sqlite3"
)
// Injectors from wire.go:
func NewProductUseCase(db *sql.DB) *product.ProductUseCase {
productRepository := product.NewProductRepository(db)
productUseCase := product.NewProductUseCase(productRepository)
return productUseCase
}
func NewUserUseCase(db *sql.DB) *user.UserUseCase {
userRepository := user.NewUserRepository(db)
userUseCase := user.NewUserUseCase(userRepository)
return userUseCase
}
// wire.go:
// Provider: a function that can produce a value.
// Sets are useful if several providers will frequently be used together.
var setRepositoryDependency = wire.NewSet(product.NewProductRepository, wire.Bind(new(product.ProductRepositoryInterface), new(*product.ProductRepository)), user.NewUserRepository, wire.Bind(new(user.UserRepositoryInterface), new(*user.UserRepository)))