Annotations¶
You can annotate functions and values with the fx.Annotate
function
before passing them to
fx.Provide
, fx.Supply
, fx.Invoke
, fx.Decorate
, or fx.Replace
.
This allows you to re-use a plain Go function to do the following without manually wrapping the function to use parameter or result objects.
Annotating a function¶
Prerequisites
A function that:
- does not accept a parameter object, when
annotating with
fx.ParamTags
. - does not return a result object when annotating
with
fx.ResultTags
.
Steps
-
Given a function that you're passing to
fx.Provide
,fx.Invoke
, orfx.Decorate
,fx.Provide( NewHTTPClient, ),
-
Wrap the function with
fx.Annotate
.fx.Provide( fx.Annotate( NewHTTPClient, ), ),
-
Inside
fx.Annotate
, pass in your annotations.fx.Provide( fx.Annotate( NewHTTPClient, fx.ResultTags(`name:"client"`), ), ),
This annotation tags the result of the function with a name.
Related resources
- fx.Annotation holds a list of all supported annotations.
Casting structs to interfaces¶
You can use function annotations to cast a struct value returned by a function into an interface consumed by another function.
Prerequisites
-
A function that produces a struct or pointer value.
func NewHTTPClient(Config) (*http.Client, error) {
-
A function that consumes the result of the producer.
func NewGitHubClient(client *http.Client) *github.Client {
-
Both functions are provided to the Fx application.
fx.Provide( NewHTTPClient, NewGitHubClient, ),
Steps
-
Declare an interface that matches the API of the produced
*http.Client
.type HTTPClient interface { Do(*http.Request) (*http.Response, error) } // This is a compile-time check that verifies // that our interface matches the API of http.Client. var _ HTTPClient = (*http.Client)(nil)
-
Change the consumer to accept the interface instead of the struct.
func NewGitHubClient(client HTTPClient) *github.Client {
-
Finally, annotate the producer with
fx.As
to state that it produces an interface value.fx.Provide( fx.Annotate( NewHTTPClient, fx.As(new(HTTPClient)), ), NewGitHubClient, ),
With this change,
- the annotated function now only puts the interface into the container
- the producer's API remains unchanged
- the consumer is decoupled from the implementation and independently testable