feat: add golang-dependency-injection skill and supporting documentation
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
# google/wire — Compile-Time Code Generation
|
||||
|
||||
Wire uses code generation to resolve the dependency graph at compile time. Type-safe, but requires a build step.
|
||||
|
||||
- Docs: [github.com/google/wire](https://github.com/google/wire) | [User Guide](https://github.com/google/wire/blob/main/docs/guide.md)
|
||||
|
||||
Before writing Wire code, refer to the library's official documentation for up-to-date API signatures and examples.
|
||||
|
||||
## Provider Definitions
|
||||
|
||||
```go
|
||||
// providers.go
|
||||
package wire
|
||||
|
||||
import "github.com/google/wire"
|
||||
|
||||
// ProviderSet groups related providers
|
||||
var InfraSet = wire.NewSet(
|
||||
NewConfig,
|
||||
NewDatabase,
|
||||
NewCache,
|
||||
)
|
||||
|
||||
var ServiceSet = wire.NewSet(
|
||||
NewUserService,
|
||||
wire.Bind(new(UserStore), new(*PostgresUserStore)), // bind interface to impl
|
||||
)
|
||||
```
|
||||
|
||||
## Injector Definition
|
||||
|
||||
```go
|
||||
// wire.go — build constraint ensures this is only used by the wire tool
|
||||
//go:build wireinject
|
||||
|
||||
package main
|
||||
|
||||
import "github.com/google/wire"
|
||||
|
||||
func InitializeApp() (*App, error) {
|
||||
wire.Build(
|
||||
InfraSet,
|
||||
ServiceSet,
|
||||
NewApp,
|
||||
)
|
||||
return nil, nil // wire replaces this body
|
||||
}
|
||||
```
|
||||
|
||||
## Generated Code
|
||||
|
||||
Run `wire ./...` to produce `wire_gen.go`:
|
||||
|
||||
```go
|
||||
// wire_gen.go — DO NOT EDIT (auto-generated by wire)
|
||||
func InitializeApp() (*App, error) {
|
||||
config := NewConfig()
|
||||
database, err := NewDatabase(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cache := NewCache(config)
|
||||
store := NewPostgresUserStore(database)
|
||||
userService := NewUserService(store, cache)
|
||||
app := NewApp(userService)
|
||||
return app, nil
|
||||
}
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
Wire generates plain constructors, so testing uses manual injection — no container to clone:
|
||||
|
||||
```go
|
||||
func TestUserService(t *testing.T) {
|
||||
mock := &MockUserStore{...}
|
||||
svc := NewUserService(mock, NewTestCache())
|
||||
// ... test
|
||||
}
|
||||
```
|
||||
|
||||
## Tradeoffs
|
||||
|
||||
- Errors caught at compile time (codegen fails if graph is incomplete)
|
||||
- Requires running `wire ./...` after every dependency change
|
||||
- No lazy loading — all dependencies created eagerly
|
||||
- No built-in lifecycle management (health checks, shutdown)
|
||||
- No runtime container — wire generates plain Go constructor calls
|
||||
- Interface bindings require explicit `wire.Bind` declarations
|
||||
- Generated files (`wire_gen.go`) must be committed and kept in sync
|
||||
|
||||
Wire injectors MUST use `//go:build wireinject` build constraint. Generated `wire_gen.go` MUST NOT be edited manually — always regenerate with `wire ./...`.
|
||||
Reference in New Issue
Block a user