Skip to content

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

wire
wire
//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{}
}
wire_gen
// 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)))

References

  1. Hire GitHub
  2. Build Constraints
  3. Compile-time Dependency Injection With Go Cloud's Wire