README

🦄 Fx GoDoc Github release Build Status Coverage Status Go Report Card

An application framework for Go that:

  • Makes dependency injection easy.
  • Eliminates the need for global state and func init().

Installation

We recommend locking to SemVer range ^1 using Glide:

glide get 'go.uber.org/fx#^1'

Alternatively you can add it as a dependency using go mod:

go get go.uber.org/fx@v1

Or by using dep:

dep ensure -add go.uber.org/fx@1.0.0

Stability

This library is v1 and follows SemVer strictly.

No breaking changes will be made to exported APIs before v2.0.0.

This project follows the Go Release Policy. Each major version of Go is supported until there are two newer major releases.

Documentation

Overview

Package fx is a framework that makes it easy to build applications out of reusable, composable modules.

Fx applications use dependency injection to eliminate globals without the tedium of manually wiring together function calls. Unlike other approaches to dependency injection, Fx works with plain Go functions: you don't need to use struct tags or embed special types, so Fx automatically works well with most Go packages.

Basic usage is explained in the package-level example below. If you're new to Fx, start there! Advanced features, including named instances, optional parameters, and value groups, are explained under the In and Out types.

Testing Fx Applications

To test functions that use the Lifecycle type or to write end-to-end tests of your Fx application, use the helper functions and types provided by the go.uber.org/fx/fxtest package.

Example
Output:

Executing NewLogger.
Executing NewMux.
Executing NewHandler.
Starting HTTP server.
Got a request.
Stopping HTTP server.

Index

Examples

Constants

View Source
const DefaultTimeout = 15 * time.Second

    DefaultTimeout is the default timeout for starting or stopping an application. It can be configured with the StartTimeout and StopTimeout options.

    View Source
    const Version = "1.13.1"

      Version is exported for runtime compatibility checks.

      Variables

      View Source
      var NopLogger = Logger(nopLogger{})

        NopLogger disables the application's log output. Note that this makes some failures difficult to debug, since no errors are printed to console.

        Functions

        func ValidateApp

        func ValidateApp(opts ...Option) error

          ValidateApp validates that supplied graph would run and is not missing any dependencies. This method does not invoke actual input functions.

          func VisualizeError

          func VisualizeError(err error) (string, error)

            VisualizeError returns the visualization of the error if available.

            Types

            type Annotated

            type Annotated struct {
            	// If specified, this will be used as the name for all non-error values returned
            	// by the constructor. For more information on named values, see the documentation
            	// for the fx.Out type.
            	//
            	// A name option may not be provided if a group option is provided.
            	Name string
            
            	// If specified, this will be used as the group name for all non-error values returned
            	// by the constructor. For more information on value groups, see the package documentation.
            	//
            	// A group option may not be provided if a name option is provided.
            	//
            	// Similar to group tags, the group name may be followed by a `,flatten`
            	// option to indicate that each element in the slice returned by the
            	// constructor should be injected into the value group individually.
            	Group string
            
            	// Target is the constructor or value being annotated with fx.Annotated.
            	Target interface{}
            }

              Annotated annotates a constructor provided to Fx with additional options.

              For example,

              func NewReadOnlyConnection(...) (*Connection, error)
              
              fx.Provide(fx.Annotated{
                Name: "ro",
                Target: NewReadOnlyConnection,
              })
              

              Is equivalent to,

              type result struct {
                fx.Out
              
                Connection *Connection `name:"ro"`
              }
              
              fx.Provide(func(...) (result, error) {
                conn, err := NewReadOnlyConnection(...)
                return result{Connection: conn}, err
              })
              

              Annotated cannot be used with constructors which produce fx.Out objects.

              When used with fx.Supply, the target is a value rather than a constructor function.

              func (Annotated) String

              func (a Annotated) String() string

              type App

              type App struct {
              	// contains filtered or unexported fields
              }

                An App is a modular application built around dependency injection. Most users will only need to use the New constructor and the all-in-one Run convenience method. In more unusual cases, users may need to use the Err, Start, Done, and Stop methods by hand instead of relying on Run.

                New creates and initializes an App. All applications begin with a constructor for the Lifecycle type already registered.

                In addition to that built-in functionality, users typically pass a handful of Provide options and one or more Invoke options. The Provide options teach the application how to instantiate a variety of types, and the Invoke options describe how to initialize the application.

                When created, the application immediately executes all the functions passed via Invoke options. To supply these functions with the parameters they need, the application looks for constructors that return the appropriate types; if constructors for any required types are missing or any invocations return an error, the application will fail to start (and Err will return a descriptive error message).

                Once all the invocations (and any required constructors) have been called, New returns and the application is ready to be started using Run or Start. On startup, it executes any OnStart hooks registered with its Lifecycle. OnStart hooks are executed one at a time, in order, and must all complete within a configurable deadline (by default, 15 seconds). For details on the order in which OnStart hooks are executed, see the documentation for the Start method.

                At this point, the application has successfully started up. If started via Run, it will continue operating until it receives a shutdown signal from Done (see the Done documentation for details); if started explicitly via Start, it will operate until the user calls Stop. On shutdown, OnStop hooks execute one at a time, in reverse order, and must all complete within a configurable deadline (again, 15 seconds by default).

                func New

                func New(opts ...Option) *App

                  New creates and initializes an App, immediately executing any functions registered via Invoke options. See the documentation of the App struct for details on the application's initialization, startup, and shutdown logic.

                  func (*App) Done

                  func (app *App) Done() <-chan os.Signal

                    Done returns a channel of signals to block on after starting the application. Applications listen for the SIGINT and SIGTERM signals; during development, users can send the application SIGTERM by pressing Ctrl-C in the same terminal as the running process.

                    Alternatively, a signal can be broadcast to all done channels manually by using the Shutdown functionality (see the Shutdowner documentation for details).

                    func (*App) Err

                    func (app *App) Err() error

                      Err returns any error encountered during New's initialization. See the documentation of the New method for details, but typical errors include missing constructors, circular dependencies, constructor errors, and invocation errors.

                      Most users won't need to use this method, since both Run and Start short-circuit if initialization failed.

                      func (*App) Run

                      func (app *App) Run()

                        Run starts the application, blocks on the signals channel, and then gracefully shuts the application down. It uses DefaultTimeout to set a deadline for application startup and shutdown, unless the user has configured different timeouts with the StartTimeout or StopTimeout options. It's designed to make typical applications simple to run.

                        However, all of Run's functionality is implemented in terms of the exported Start, Done, and Stop methods. Applications with more specialized needs can use those methods directly instead of relying on Run.

                        func (*App) Start

                        func (app *App) Start(ctx context.Context) error

                          Start kicks off all long-running goroutines, like network servers or message queue consumers. It does this by interacting with the application's Lifecycle.

                          By taking a dependency on the Lifecycle type, some of the user-supplied functions called during initialization may have registered start and stop hooks. Because initialization calls constructors serially and in dependency order, hooks are naturally registered in dependency order too.

                          Start executes all OnStart hooks registered with the application's Lifecycle, one at a time and in order. This ensures that each constructor's start hooks aren't executed until all its dependencies' start hooks complete. If any of the start hooks return an error, Start short-circuits, calls Stop, and returns the inciting error.

                          Note that Start short-circuits immediately if the New constructor encountered any errors in application initialization.

                          func (*App) StartTimeout

                          func (app *App) StartTimeout() time.Duration

                            StartTimeout returns the configured startup timeout. Apps default to using DefaultTimeout, but users can configure this behavior using the StartTimeout option.

                            func (*App) Stop

                            func (app *App) Stop(ctx context.Context) error

                              Stop gracefully stops the application. It executes any registered OnStop hooks in reverse order, so that each constructor's stop hooks are called before its dependencies' stop hooks.

                              If the application didn't start cleanly, only hooks whose OnStart phase was called are executed. However, all those hooks are executed, even if some fail.

                              func (*App) StopTimeout

                              func (app *App) StopTimeout() time.Duration

                                StopTimeout returns the configured shutdown timeout. Apps default to using DefaultTimeout, but users can configure this behavior using the StopTimeout option.

                                type DotGraph

                                type DotGraph string

                                  DotGraph contains a DOT language visualization of the dependency graph in an Fx application. It is provided in the container by default at initialization. On failure to build the dependency graph, it is attached to the error and if possible, colorized to highlight the root cause of the failure.

                                  type ErrorHandler

                                  type ErrorHandler interface {
                                  	HandleError(error)
                                  }

                                    ErrorHandler handles Fx application startup errors.

                                    type Hook

                                    type Hook struct {
                                    	OnStart func(context.Context) error
                                    	OnStop  func(context.Context) error
                                    }

                                      A Hook is a pair of start and stop callbacks, either of which can be nil. If a Hook's OnStart callback isn't executed (because a previous OnStart failure short-circuited application startup), its OnStop callback won't be executed.

                                      type In

                                      type In struct{ dig.In }

                                      In can be embedded in a constructor's parameter struct to take advantage of advanced dependency injection features.

                                      Modules should take a single parameter struct that embeds an In in order to provide a forward-compatible API: since adding fields to a struct is backward-compatible, modules can then add optional dependencies in minor releases.

                                      Parameter Structs

                                      Fx constructors declare their dependencies as function parameters. This can quickly become unreadable if the constructor has a lot of dependencies.

                                      func NewHandler(users *UserGateway, comments *CommentGateway, posts *PostGateway, votes *VoteGateway, authz *AuthZGateway) *Handler {
                                        // ...
                                      }
                                      

                                      To improve the readability of constructors like this, create a struct that lists all the dependencies as fields and change the function to accept that struct instead. The new struct is called a parameter struct.

                                      Fx has first class support for parameter structs: any struct embedding fx.In gets treated as a parameter struct, so the individual fields in the struct are supplied via dependency injection. Using a parameter struct, we can make the constructor above much more readable:

                                      type HandlerParams struct {
                                        fx.In
                                      
                                        Users    *UserGateway
                                        Comments *CommentGateway
                                        Posts    *PostGateway
                                        Votes    *VoteGateway
                                        AuthZ    *AuthZGateway
                                      }
                                      
                                      func NewHandler(p HandlerParams) *Handler {
                                        // ...
                                      }
                                      

                                      Though it's rarely a good idea, constructors can receive any combination of parameter structs and parameters.

                                      func NewHandler(p HandlerParams, l *log.Logger) *Handler {
                                        // ...
                                      }
                                      

                                      Optional Dependencies

                                      Constructors often have soft dependencies on some types: if those types are missing, they can operate in a degraded state. Fx supports optional dependencies via the `optional:"true"` tag to fields on parameter structs.

                                      type UserGatewayParams struct {
                                        fx.In
                                      
                                        Conn  *sql.DB
                                        Cache *redis.Client `optional:"true"`
                                      }
                                      

                                      If an optional field isn't available in the container, the constructor receives the field's zero value.

                                      func NewUserGateway(p UserGatewayParams, log *log.Logger) (*UserGateway, error) {
                                        if p.Cache == nil {
                                          log.Print("Caching disabled")
                                        }
                                        // ...
                                      }
                                      

                                      Constructors that declare optional dependencies MUST gracefully handle situations in which those dependencies are absent.

                                      The optional tag also allows adding new dependencies without breaking existing consumers of the constructor.

                                      Named Values

                                      Some use cases require the application container to hold multiple values of the same type. For details on producing named values, see the documentation for the Out type.

                                      Fx allows functions to consume named values via the `name:".."` tag on parameter structs. Note that both the name AND type of the fields on the parameter struct must match the corresponding result struct.

                                      type GatewayParams struct {
                                        fx.In
                                      
                                        WriteToConn  *sql.DB `name:"rw"`
                                        ReadFromConn *sql.DB `name:"ro"`
                                      }
                                      

                                      The name tag may be combined with the optional tag to declare the dependency optional.

                                      type GatewayParams struct {
                                        fx.In
                                      
                                        WriteToConn  *sql.DB `name:"rw"`
                                        ReadFromConn *sql.DB `name:"ro" optional:"true"`
                                      }
                                      
                                      func NewCommentGateway(p GatewayParams, log *log.Logger) (*CommentGateway, error) {
                                        if p.ReadFromConn == nil {
                                          log.Print("Warning: Using RW connection for reads")
                                          p.ReadFromConn = p.WriteToConn
                                        }
                                        // ...
                                      }
                                      

                                      Value Groups

                                      To make it easier to produce and consume many values of the same type, Fx supports named, unordered collections called value groups. For details on producing value groups, see the documentation for the Out type.

                                      Functions can depend on a value group by requesting a slice tagged with `group:".."`. This will execute all constructors that provide a value to that group in an unspecified order, then collect all the results into a single slice. Keep in mind that this makes the types of the parameter and result struct fields different: if a group of constructors each returns type T, parameter structs consuming the group must use a field of type []T.

                                      type ServerParams struct {
                                        fx.In
                                      
                                        Handlers []Handler `group:"server"`
                                      }
                                      
                                      func NewServer(p ServerParams) *Server {
                                        server := newServer()
                                        for _, h := range p.Handlers {
                                          server.Register(h)
                                        }
                                        return server
                                      }
                                      

                                      Note that values in a value group are unordered. Fx makes no guarantees about the order in which these values will be produced.

                                      type Lifecycle

                                      type Lifecycle interface {
                                      	Append(Hook)
                                      }

                                        Lifecycle allows constructors to register callbacks that are executed on application start and stop. See the documentation for App for details on Fx applications' initialization, startup, and shutdown logic.

                                        type Option

                                        type Option interface {
                                        	fmt.Stringer
                                        	// contains filtered or unexported methods
                                        }

                                          An Option configures an App using the functional options paradigm popularized by Rob Pike. If you're unfamiliar with this style, see https://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html.

                                          func Error

                                          func Error(errs ...error) Option

                                            Error registers any number of errors with the application to short-circuit startup. If more than one error is given, the errors are combined into a single error.

                                            Similar to invocations, errors are applied in order. All Provide and Invoke options registered before or after an Error option will not be applied.

                                            Example
                                            Output:
                                            
                                            $PORT is not set
                                            

                                            func ErrorHook

                                            func ErrorHook(funcs ...ErrorHandler) Option

                                              ErrorHook registers error handlers that implement error handling functions. They are executed on invoke failures. Passing multiple ErrorHandlers appends the new handlers to the application's existing list.

                                              func Extract

                                              func Extract(target interface{}) Option

                                                Extract fills the given struct with values from the dependency injection container on application initialization. The target MUST be a pointer to a struct. Only exported fields will be filled.

                                                Extract will be deprecated soon: use Populate instead, which doesn't require defining a container struct.

                                                func Invoke

                                                func Invoke(funcs ...interface{}) Option

                                                  Invoke registers functions that are executed eagerly on application start. Arguments for these invocations are built using the constructors registered by Provide. Passing multiple Invoke options appends the new invocations to the application's existing list.

                                                  Unlike constructors, invocations are always executed, and they're always run in order. Invocations may have any number of returned values. If the final returned object is an error, it's assumed to be a success indicator. All other returned values are discarded.

                                                  Typically, invoked functions take a handful of high-level objects (whose constructors depend on lower-level objects) and introduce them to each other. This kick-starts the application by forcing it to instantiate a variety of types.

                                                  To see an invocation in use, read through the package-level example. For advanced features, including optional parameters and named instances, see the documentation of the In and Out types.

                                                  func Logger

                                                  func Logger(p Printer) Option

                                                    Logger redirects the application's log output to the provided printer.

                                                    func Options

                                                    func Options(opts ...Option) Option

                                                      Options converts a collection of Options into a single Option. This allows packages to bundle sophisticated functionality into easy-to-use Fx modules. For example, a logging package might export a simple option like this:

                                                      package logging
                                                      
                                                      var Module = fx.Provide(func() *log.Logger {
                                                        return log.New(os.Stdout, "", 0)
                                                      })
                                                      

                                                      A shared all-in-one microservice package could then use Options to bundle logging with similar metrics, tracing, and gRPC modules:

                                                      package server
                                                      
                                                      var Module = fx.Options(
                                                        logging.Module,
                                                        metrics.Module,
                                                        tracing.Module,
                                                        grpc.Module,
                                                      )
                                                      

                                                      Since this all-in-one module has a minimal API surface, it's easy to add new functionality to it without breaking existing users. Individual applications can take advantage of all this functionality with only one line of code:

                                                      app := fx.New(server.Module)
                                                      

                                                      Use this pattern sparingly, since it limits the user's ability to customize their application.

                                                      func Populate

                                                      func Populate(targets ...interface{}) Option

                                                        Populate sets targets with values from the dependency injection container during application initialization. All targets must be pointers to the values that must be populated. Pointers to structs that embed In are supported, which can be used to populate multiple values in a struct.

                                                        This is most helpful in unit tests: it lets tests leverage Fx's automatic constructor wiring to build a few structs, but then extract those structs for further testing.

                                                        Example
                                                        Output:
                                                        
                                                        john
                                                        

                                                        func Provide

                                                        func Provide(constructors ...interface{}) Option

                                                          Provide registers any number of constructor functions, teaching the application how to instantiate various types. The supplied constructor function(s) may depend on other types available in the application, must return one or more objects, and may return an error. For example:

                                                          // Constructs type *C, depends on *A and *B.
                                                          func(*A, *B) *C
                                                          
                                                          // Constructs type *C, depends on *A and *B, and indicates failure by
                                                          // returning an error.
                                                          func(*A, *B) (*C, error)
                                                          
                                                          // Constructs types *B and *C, depends on *A, and can fail.
                                                          func(*A) (*B, *C, error)
                                                          

                                                          The order in which constructors are provided doesn't matter, and passing multiple Provide options appends to the application's collection of constructors. Constructors are called only if one or more of their returned types are needed, and their results are cached for reuse (so instances of a type are effectively singletons within an application). Taken together, these properties make it perfectly reasonable to Provide a large number of constructors even if only a fraction of them are used.

                                                          See the documentation of the In and Out types for advanced features, including optional parameters and named instances.

                                                          Constructor functions should perform as little external interaction as possible, and should avoid spawning goroutines. Things like server listen loops, background timer loops, and background processing goroutines should instead be managed using Lifecycle callbacks.

                                                          func StartTimeout

                                                          func StartTimeout(v time.Duration) Option

                                                            StartTimeout changes the application's start timeout.

                                                            func StopTimeout

                                                            func StopTimeout(v time.Duration) Option

                                                              StopTimeout changes the application's stop timeout.

                                                              func Supply

                                                              func Supply(values ...interface{}) Option

                                                                Supply provides instantiated values for dependency injection as if they had been provided using a constructor that simply returns them. The most specific type of each value (as determined by reflection) is used.

                                                                For example, given:

                                                                type (
                                                                	TypeA struct{}
                                                                	TypeB struct{}
                                                                	TypeC struct{}
                                                                )
                                                                
                                                                var a, b, c = &TypeA{}, TypeB{}, &TypeC{}
                                                                

                                                                The following two forms are equivalent:

                                                                fx.Supply(a, b, fx.Annotated{Target: c})
                                                                
                                                                fx.Provide(
                                                                	func() *TypeA { return a },
                                                                	func() TypeB { return b },
                                                                	fx.Annotated{Target: func() *TypeC { return c }},
                                                                )
                                                                

                                                                Supply panics if a value (or annotation target) is an untyped nil or an error.

                                                                type Out

                                                                type Out struct{ dig.Out }

                                                                Out is the inverse of In: it can be embedded in result structs to take advantage of advanced features.

                                                                Modules should return a single result struct that embeds an Out in order to provide a forward-compatible API: since adding fields to a struct is backward-compatible, minor releases can provide additional types.

                                                                Result Structs

                                                                Result structs are the inverse of parameter structs (discussed in the In documentation). These structs represent multiple outputs from a single function as fields. Fx treats all structs embedding fx.Out as result structs, so other constructors can rely on the result struct's fields directly.

                                                                Without result structs, we sometimes have function definitions like this:

                                                                func SetupGateways(conn *sql.DB) (*UserGateway, *CommentGateway, *PostGateway, error) {
                                                                  // ...
                                                                }
                                                                

                                                                With result structs, we can make this both more readable and easier to modify in the future:

                                                                type Gateways struct {
                                                                  fx.Out
                                                                
                                                                  Users    *UserGateway
                                                                  Comments *CommentGateway
                                                                  Posts    *PostGateway
                                                                }
                                                                
                                                                func SetupGateways(conn *sql.DB) (Gateways, error) {
                                                                  // ...
                                                                }
                                                                

                                                                Named Values

                                                                Some use cases require the application container to hold multiple values of the same type. For details on consuming named values, see the documentation for the In type.

                                                                A constructor that produces a result struct can tag any field with `name:".."` to have the corresponding value added to the graph under the specified name. An application may contain at most one unnamed value of a given type, but may contain any number of named values of the same type.

                                                                type ConnectionResult struct {
                                                                  fx.Out
                                                                
                                                                  ReadWrite *sql.DB `name:"rw"`
                                                                  ReadOnly  *sql.DB `name:"ro"`
                                                                }
                                                                
                                                                func ConnectToDatabase(...) (ConnectionResult, error) {
                                                                  // ...
                                                                  return ConnectionResult{ReadWrite: rw, ReadOnly:  ro}, nil
                                                                }
                                                                

                                                                Value Groups

                                                                To make it easier to produce and consume many values of the same type, Fx supports named, unordered collections called value groups. For details on consuming value groups, see the documentation for the In type.

                                                                Constructors can send values into value groups by returning a result struct tagged with `group:".."`.

                                                                type HandlerResult struct {
                                                                  fx.Out
                                                                
                                                                  Handler Handler `group:"server"`
                                                                }
                                                                
                                                                func NewHelloHandler() HandlerResult {
                                                                  // ...
                                                                }
                                                                
                                                                func NewEchoHandler() HandlerResult {
                                                                  // ...
                                                                }
                                                                

                                                                Any number of constructors may provide values to this named collection, but the ordering of the final collection is unspecified. Keep in mind that value groups require parameter and result structs to use fields with different types: if a group of constructors each returns type T, parameter structs consuming the group must use a field of type []T.

                                                                To provide multiple values for a group from a result struct, produce a slice and use the `,flatten` option on the group tag. This indicates that each element in the slice should be injected into the group individually.

                                                                type IntResult struct {
                                                                  fx.Out
                                                                
                                                                  Handler []int `group:"server"`         // Consume as [][]int
                                                                  Handler []int `group:"server,flatten"` // Consume as []int
                                                                }
                                                                

                                                                type Printer

                                                                type Printer interface {
                                                                	Printf(string, ...interface{})
                                                                }

                                                                  Printer is the interface required by Fx's logging backend. It's implemented by most loggers, including the one bundled with the standard library.

                                                                  type ShutdownOption

                                                                  type ShutdownOption interface {
                                                                  	// contains filtered or unexported methods
                                                                  }

                                                                    ShutdownOption provides a way to configure properties of the shutdown process. Currently, no options have been implemented.

                                                                    type Shutdowner

                                                                    type Shutdowner interface {
                                                                    	Shutdown(...ShutdownOption) error
                                                                    }

                                                                      Shutdowner provides a method that can manually trigger the shutdown of the application by sending a signal to all open Done channels. Shutdowner works on applications using Run as well as Start, Done, and Stop. The Shutdowner is provided to all Fx applications.

                                                                      Directories

                                                                      Path Synopsis
                                                                      internal