dig

package module
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 19, 2017 License: MIT Imports: 6 Imported by: 1,288

README

dig: Dependency Injection Framework for Go

GoDoc Coverage Status Build Status Report Card

package dig provides an opinionated way of resolving object dependencies.

Status

BETA. Expect potential API changes.

Container

package dig exposes type Container as an object capable of resolving a directional dependency graph.

To create one:

import "go.uber.org/dig"

func main() {
	c := dig.New()
	// dig container `c` is ready to use!
}

All objects in the container are treated as a singletons, meaning there can be only one object in the graph of a given type.

There are plans to expand the API to support multiple objects of the same type in the container, but for time being consider using a factory pattern.

Provide

The Provide method adds a constructor of an object (or objects), to the container. A constructor can be a function returning any number of objects and, optionally, an error.

Each argument to the constructor is registered as a dependency in the graph.

type A struct {}
type B struct {}
type C struct {}

c := dig.New()
constructor := func (*A, *B) *C {
  // At this point, *A and *B have been resolved through the graph
  // and can be used to provide an object of type *C
  return &C{}
}
err := c.Provide(constructor)
// dig container is now able to provide *C to any constructor.
//
// However, note that in the current example *A and *B
// have not been provided, meaning that the resolution of type
// *C will result in an error, because types *A and *B can not
// be instantiated.
Advanced Provide

// TODO: docs on dig.In usage // TODO: docs on dig.Out usage

Invoke

The Invoke API is the flip side of Provide and used to retrieve types from the container.

Invoke looks through the graph and resolves all the constructor parameters for execution.

In order to successfully use use Invoke, the function must meet the following criteria:

  1. Input to the Invoke must be a function
  2. All arguments to the function must be types in the container
  3. If an error is returned from an invoked function, it will be propagated to the caller

Here is a fully working somewhat real-world Invoke example:

package main

import (
	"go.uber.org/config"
	"go.uber.org/dig"
	"go.uber.org/zap"
)

func main() {
	c := dig.New()

	// Provide configuration object
	c.Provide(func() config.Provider {
		return config.NewYAMLProviderFromBytes([]byte("tag: Hello, world!"))
	})

	// Provide a zap logger which relies on configuration
	c.Provide(func(cfg config.Provider) (*zap.Logger, error) {
		l, err := zap.NewDevelopment()
		if err != nil {
			return nil, err
		}
		return l.With(zap.String("iconic phrase", cfg.Get("tag").AsString())), nil
	})

	// Invoke a function that requires a zap logger, which in turn requires config
	c.Invoke(func(l *zap.Logger) {
		l.Info("You've been invoked")
		// Logger output:
		//     INFO    You've been invoked     {"iconic phrase": "Hello, world!"}
		//
		// As we can see, Invoke caused the Logger to be created, which in turn
		// required the configuration to be created.
	})
}

Documentation

Overview

Package dig is the dig: Dependency Injection Framework for Go.

package dig provides an opinionated way of resolving object dependencies.

Status

BETA. Expect potential API changes.

Container

package dig exposes type Container as an object capable of resolving a directional dependency graph.

To create one:

import "go.uber.org/dig"

func main() {
	c := dig.New()
	// dig container `c` is ready to use!
}

**All objects in the container are treated as a singletons**, meaning there can be only one object in the graph of a given type.

There are plans to expand the API to support multiple objects of the same type in the container, but for time being consider using a factory pattern.

Provide

The Provide method adds a constructor of an object (or objects), to the container. A constructor can be a function returning any number of objects and, optionally, an error.

Each argument to the constructor is registered as a **dependency** in the graph.

type A struct {}
type B struct {}
type C struct {}

c := dig.New()
constructor := func (*A, *B) *C {
  // At this point, *A and *B have been resolved through the graph
  // and can be used to provide an object of type *C
  return &C{}
}
err := c.Provide(constructor)
// dig container is now able to provide *C to any constructor.
//
// However, note that in the current example *A and *B
// have not been provided, meaning that the resolution of type
// *C will result in an error, because types *A and *B can not
// be instantiated.

Advanced Provide

// TODO: docs on dig.In usage // TODO: docs on dig.Out usage

Invoke

The Invoke API is the flip side of Provide and used to retrieve types from the container.

Invoke looks through the graph and resolves all the constructor parameters for execution.

In order to successfully use use Invoke, the function must meet the following criteria:

• Input to the Invoke must be a function

• All arguments to the function must be types in the container

• If an error is returned from an invoked function, it will be propagated to the caller

Here is a fully working somewhat real-world Invoke example:

package main

import (
	"go.uber.org/config"
	"go.uber.org/dig"
	"go.uber.org/zap"
)

func main() {
	c := dig.New()

	// Provide configuration object
	c.Provide(func() config.Provider {
		return config.NewYAMLProviderFromBytes([]byte("tag: Hello, world!"))
	})

	// Provide a zap logger which relies on configuration
	c.Provide(func(cfg config.Provider) (*zap.Logger, error) {
		l, err := zap.NewDevelopment()
		if err != nil {
			return nil, err
		}
		return l.With(zap.String("iconic phrase", cfg.Get("tag").AsString())), nil
	})

	// Invoke a function that requires a zap logger, which in turn requires config
	c.Invoke(func(l *zap.Logger) {
		l.Info("You've been invoked")
		// Logger output:
		//     INFO    You've been invoked     {"iconic phrase": "Hello, world!"}
		//
		// As we can see, Invoke caused the Logger to be created, which in turn
		// required the configuration to be created.
	})
}

Index

Constants

View Source
const Version = "0.5.0"

Version of the library

Variables

This section is empty.

Functions

This section is empty.

Types

type Container

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

A Container is a directed, acyclic graph of dependencies. Dependencies are constructed on-demand and returned from a cache thereafter, so they're effectively singletons.

func New

func New() *Container

New constructs a ready-to-use Container.

func (*Container) Invoke

func (c *Container) Invoke(function interface{}) error

Invoke runs a function, supplying its arguments from the Container. If the function's last return value is an error, that error is propagated to the caller. All other returned values (if any) are ignored.

Passing anything other than a function to Invoke returns an error immediately.

func (*Container) Provide

func (c *Container) Provide(constructor interface{}) error

Provide teaches the Container how to construct one or more new types. It accepts either a constructor function or an already-constructed object.

Any function passed to Provide is assumed to be a constructor. Constructors can take any number of parameters, which will be supplied by the Container on demand. They must return at least one non-error value, all of which are then available in the Container. If the last returned value is an error, the Container inspects it to determine whether the constructor succeeded or failed. Regardless of position, returned errors are never put into the Container's dependency graph.

All non-functions (including structs, pointers, Go's built-in collections, and primitive types like ints) are inserted into the Container as-is.

func (*Container) String

func (c *Container) String() string

String representation of the entire Container

type In

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

In is an embeddable object that signals to dig that the struct should be treated differently. Instead of itself becoming an object in the graph, memebers of the struct are inserted into the graph.

Tags on those memebers control their behavior. For example,

type Input struct {
  dig.In

  S *Something
  T *Thingy `optional:"true"`
}

type Out

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

Out is an embeddable type that signals to dig that the returned struct should be treated differently. Instead of the struct itself becoming part of the container, all members of the struct will.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL