Skip to content

Wire

Google's own compile time dependency injection framework is called: Wire. Wire works a little bit different from guice for example. Wire generates code from a file called wire.go to a file called wire_gen.go, which can be used in the main.go file to initialize and start the application.

Install wire first:

go install github.com/google/wire/cmd/wire@latest

Let's take our example from the chapter before. We first just create a file called wire.go:

wire.go
//go:build wireinject
// +build wireinject

package main

import (
    "dependency_injection/core/ports"
    "dependency_injection/infrastructure/services"
    "dependency_injection/interface/controllers"
    "github.com/google/wire"
    "os"
)

func NewTTSService() ports.TTSServicePort {
    if os.Getenv("ENV") == "prod" {
        return services.NewRealTTSService()
    } else {
        return services.NewFakeTTSService()
    }
}

func InitializeMainController() *controllers.MainController {
    wire.Build(NewTTSService, controllers.NewMainController)
    return &controllers.MainController{}
}

After that we can run wire to generate a wire_gen.go file:

Run in project root
wire
wire_gen.go
// 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 (
    "dependency_injection/core/ports"
    "dependency_injection/infrastructure/services"
    "dependency_injection/interface/controllers"
    "os"
)

// Injectors from wire.go:

func InitializeMainController() *controllers.MainController {
    ttsServicePort := NewTTSService()
    mainController := controllers.NewMainController(ttsServicePort)
    return mainController
}

// wire.go:

func NewTTSService() ports.TTSServicePort {
    if os.Getenv("ENV") == "prod" {
        return services.NewRealTTSService()
    } else {
        return services.NewFakeTTSService()
    }
}

And now we can adapt the main.go file:

main.go
1
2
3
4
5
6
func main() {
    mainController := InitializeMainController()
    http.HandleFunc("/say", mainController.Say)
    log.Println("Running server on http://localhost:8081")
    log.Fatal(http.ListenAndServe(":8081", nil))
}

Since we have now two files for the main package, we need to adapt our start line. This is important because otherwise it won't compile properly:

go run main.go wire_gen.go