docs(depinject): clarify depinject API (#12214)
This commit is contained in:
parent
0f8f4ec9a8
commit
467d72be0c
@ -7,7 +7,8 @@ to simplify the definition of a blockchain by replacing most of app.go's boilerp
|
||||
|
||||
## Usage
|
||||
|
||||
### `depinject` example
|
||||
`depinject` includes an expressive and composable [Configuration API](https://pkg.go.dev/github.com/cosmos/cosmos-sdk/depinject#Config).
|
||||
A core configuration is `Provide`, for example this code snippet
|
||||
|
||||
```go
|
||||
package main
|
||||
@ -39,6 +40,93 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
demonstrates the registration of free **provider functions** via the `Provide` API. Provider functions form the basis of the
|
||||
dependency tree, they are introspected then their inputs identified as dependencies and outputs as dependants, either for
|
||||
another provider function or state stored outside the DI container, as is the case of `&x` and `&y` above.
|
||||
|
||||
### Interface type resolution
|
||||
|
||||
`depinject` supports interface types as inputs to provider functions. In the SDK's case this pattern is used to decouple
|
||||
`Keeper` dependencies between modules. For example `x/bank` expects an [AccountKeeper](https://pkg.go.dev/github.com/cosmos/cosmos-sdk/x/bank/types#AccountKeeper) interface as [input to provideModule](https://github.com/cosmos/cosmos-sdk/blob/de343d458aa68c19630177807d6f0e2e6deaf7a9/x/bank/module.go#L224).
|
||||
Concretely `SimApp` uses the implementation in `x/auth`, but this design allows for this loose coupling to change.
|
||||
|
||||
Given the following types
|
||||
|
||||
```golang
|
||||
package duck
|
||||
|
||||
type Duck interface {
|
||||
quack()
|
||||
}
|
||||
|
||||
type AlsoDuck interface {
|
||||
quack()
|
||||
}
|
||||
|
||||
type Mallard struct{}
|
||||
type Canvasback struct{}
|
||||
|
||||
func (duck Mallard) quack() {}
|
||||
func (duck Canvasback) quack() {}
|
||||
|
||||
type Pond struct {
|
||||
Duck AlsoDuck
|
||||
}
|
||||
```
|
||||
|
||||
This usage
|
||||
|
||||
```golang
|
||||
var pond Pond
|
||||
|
||||
depinject.Inject(
|
||||
depinject.Provide(
|
||||
func() Mallard { return Mallard{} },
|
||||
func(duck Duck) Pond {
|
||||
return Pond{Duck: duck}
|
||||
}),
|
||||
&pond)
|
||||
```
|
||||
|
||||
results in an *implicit* binding of `Duck` to `Mallard`. This works because there is only one implementation of `Duck`
|
||||
in the container. However, adding a second provider of `Duck` will result in an error:
|
||||
|
||||
```golang
|
||||
var pond Pond
|
||||
|
||||
depinject.Inject(
|
||||
depinject.Provide(
|
||||
func() Mallard { return Mallard{} },
|
||||
func() Canvasback { return Canvasback{} },
|
||||
func(duck Duck) Pond {
|
||||
return Pond{Duck: duck}
|
||||
}),
|
||||
&pond)
|
||||
```
|
||||
|
||||
A specific binding preference for `Duck` is required.
|
||||
|
||||
#### `BindInterface` API
|
||||
|
||||
In the above situation registering a binding for a given interface binding may look like
|
||||
|
||||
```golang
|
||||
depinject.Inject(
|
||||
depinject.Configs(
|
||||
depinject.BindInterface(
|
||||
"duck.Duck",
|
||||
"duck.Mallard"),
|
||||
depinject.Provide(
|
||||
func() Mallard { return Mallard{} },
|
||||
func() Canvasback { return Canvasback{} },
|
||||
func(duck Duck) APond {
|
||||
return Pond{Duck: duck}
|
||||
})),
|
||||
&pond)
|
||||
```
|
||||
|
||||
Now `depinject` has enough information to provide `Mallard` as an input to `APond`.
|
||||
|
||||
### Full example in real app
|
||||
|
||||
```go
|
||||
|
||||
Loading…
Reference in New Issue
Block a user