inject: github.com/facebookgo/inject Index | Examples | Files | Directories

package inject

import "github.com/facebookgo/inject"

Package inject provides a reflect based injector. A large application built with dependency injection in mind will typically involve the boring work of setting up the object graph. This library attempts to take care of this boring work by creating and connecting the various objects. Its use involves you seeding the object graph with some (possibly incomplete) objects, where the underlying types have been tagged for injection. Given this, the library will populate the objects creating new ones as necessary. It uses singletons by default, supports optional private instances as well as named instances.

It works using Go's reflection package and is inherently limited in what it can do as opposed to a code-gen system with respect to private fields.

The usage pattern for the library involves struct tags. It requires the tag format used by the various standard libraries, like json, xml etc. It involves tags in one of the three forms below:

`inject:""`
`inject:"private"`
`inject:"dev logger"`

The first no value syntax is for the common case of a singleton dependency of the associated type. The second triggers creation of a private instance for the associated type. Finally the last form is asking for a named dependency called "dev logger".

Code:

package main

import (
    "fmt"
    "net/http"
    "os"

    "github.com/facebookgo/inject"
)

// Our Awesome Application renders a message using two APIs in our fake
// world.
type HomePlanetRenderApp struct {
    // The tags below indicate to the inject library that these fields are
    // eligible for injection. They do not specify any options, and will
    // result in a singleton instance created for each of the APIs.

    NameAPI   *NameAPI   `inject:""`
    PlanetAPI *PlanetAPI `inject:""`
}

func (a *HomePlanetRenderApp) Render(id uint64) string {
    return fmt.Sprintf(
        "%s is from the planet %s.",
        a.NameAPI.Name(id),
        a.PlanetAPI.Planet(id),
    )
}

// Our fake Name API.
type NameAPI struct {
    // Here and below in PlanetAPI we add the tag to an interface value.
    // This value cannot automatically be created (by definition) and
    // hence must be explicitly provided to the graph.

    HTTPTransport http.RoundTripper `inject:""`
}

func (n *NameAPI) Name(id uint64) string {
    // in the real world we would use f.HTTPTransport and fetch the name
    return "Spock"
}

// Our fake Planet API.
type PlanetAPI struct {
    HTTPTransport http.RoundTripper `inject:""`
}

func (p *PlanetAPI) Planet(id uint64) string {
    // in the real world we would use f.HTTPTransport and fetch the planet
    return "Vulcan"
}

func main() {
    // Typically an application will have exactly one object graph, and
    // you will create it and use it within a main function:
    var g inject.Graph

    // We provide our graph two "seed" objects, one our empty
    // HomePlanetRenderApp instance which we're hoping to get filled out,
    // and second our DefaultTransport to satisfy our HTTPTransport
    // dependency. We have to provide the DefaultTransport because the
    // dependency is defined in terms of the http.RoundTripper interface,
    // and since it is an interface the library cannot create an instance
    // for it. Instead it will use the given DefaultTransport to satisfy
    // the dependency since it implements the interface:
    var a HomePlanetRenderApp
    err := g.Provide(
        &inject.Object{Value: &a},
        &inject.Object{Value: http.DefaultTransport},
    )
    if err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    // Here the Populate call is creating instances of NameAPI &
    // PlanetAPI, and setting the HTTPTransport on both to the
    // http.DefaultTransport provided above:
    if err := g.Populate(); err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }

    // There is a shorthand API for the simple case which combines the
    // three calls above is available as inject.Populate:
    //
    //   inject.Populate(&a, http.DefaultTransport)
    //
    // The above API shows the underlying API which also allows the use of
    // named instances for more complex scenarios.

    fmt.Println(a.Render(42))

}

Index

Examples

Package Files

inject.go

func Populate Uses

func Populate(values ...interface{}) error

Populate is a short-hand for populating a graph with the given incomplete object values.

type Graph Uses

type Graph struct {
    Logger Logger // Optional, will trigger debug logging.
    // contains filtered or unexported fields
}

The Graph of Objects.

func (*Graph) Objects Uses

func (g *Graph) Objects() []*Object

Objects returns all known objects, named as well as unnamed. The returned elements are not in a stable order.

func (*Graph) Populate Uses

func (g *Graph) Populate() error

Populate the incomplete Objects.

func (*Graph) Provide Uses

func (g *Graph) Provide(objects ...*Object) error

Provide objects to the Graph. The Object documentation describes the impact of various fields.

type Logger Uses

type Logger interface {
    Debugf(format string, v ...interface{})
}

Logger allows for simple logging as inject traverses and populates the object graph.

type Object Uses

type Object struct {
    Value    interface{}
    Name     string             // Optional
    Complete bool               // If true, the Value will be considered complete
    Fields   map[string]*Object // Populated with the field names that were injected and their corresponding *Object.
    // contains filtered or unexported fields
}

An Object in the Graph.

func (*Object) String Uses

func (o *Object) String() string

String representation suitable for human consumption.

Directories

PathSynopsis
injecttesta
injecttestb

Package inject imports 5 packages (graph) and is imported by 25 packages. Updated 2017-02-27. Refresh now. Tools for package owners.