Socket
Socket
Sign inDemoInstall

github.com/maxzhang1985/inject

Package Overview
Dependencies
4
Alerts
File Explorer

Install Socket

Detect and block malicious and high-risk dependencies

Install

    github.com/maxzhang1985/inject

Package inject make your dependency injection easy. Container allows you to inject dependencies into constructors or structures without the need to have specified each argument manually. First of all, when creating a new container, you need to describe how to create each instance of a dependency. To do this, use the container option inject.Provide(). Now, container knows how to create *pkg.Dependency and *pkg.AnotherDependency. For advanced providing see inject.Provide() and inject.ProvideOption documentation. After building a container, it is easy to get any previously provided type. To do this, use the container's Extract() method. The container collects a dependencies of *pkg.AnotherDependency, creates its instance and places it in a target pointer. For advanced extraction see Extract() and inject.ExtractOption documentation.


Version published

Readme

Source

Tweet

Documentation Release Build Status Code Coverage Contributors

Dependency injection container allows you to inject dependencies into constructors or structures without the need to have specified each argument manually.

This container implementation inspired by google/wire, uber-go/fx and uber-go/dig.

See godoc for feel the difference.

Contents

Installing

go get -u github.com/defval/inject

Type injection

Define constructors:

// NewHTTPHandler is a http mux constructor.
func NewHTTPServeMux() *http.ServeMux {
	return &http.ServeMux{}
}

// NewHTTPServer is a http server constructor, handler will be injected 
// by container. If environment variable `STATUS == "stoped"` extract
// server cause error.
func NewHTTPServer(handler *net.ServeMux) (*http.Server, error) {
	if os.Getenv("STATUS") == "stopped" {
		return nil, errors.New("server stoped")
	}
	
	return &http.Server{
		Handler: handler,
	}, nil
}

Build container and extract values:

// build container
container, err := inject.New(
    inject.Provide(NewHTTPServeMux), // provide mux
    inject.Provide(NewHTTPServer), // provide server
)

// don't forget to handle errors © golang

// define variable for *http.Server
var server *http.Server

// extract into this variable
container.Extract(&server)

// use it!
server.ListenAndServe()

Groups

When you have two or more implementations of same interface:

// NewUserController
func NewUserController() *UserController {
	return &UserController{}
}

// NewPostController
func NewPostController() *PostController {
	return &PostController()
}

// Controller
type Controller interface {
	RegisterRoutes()
}

Group it!

// IController is a java style interface alias =D
// inject.As(new(Controller)) looks worse in readme.
var IController = new(Controller)

container, err := inject.New(
	inject.Provide(NewUserController, inject.As(IController)),
	inject.Provide(NewPostController, inject.As(IController)),
)

var controllers []Controller
// extract all controllers
container.Extract(&controllers)

// and do something!!!
for _, ctrl := range controllers {
	ctrl.RegisterRoutes()
}

Return structs, accept interfaces!

Bind implementations as interfaces:

// NewHandler is a http mux constructor. Returns concrete
// implementation - *http.ServeMux.
func NewServeMux() *http.ServeMux {
	return &http.ServeMux{}
}

// NewServer is a http server constructor. Needs handler for 
// working.
func NewServer(handler http.Handler) *http.Server {
	return &http.Server{
		Handler: handler,
	}
}

Provide concrete implementation as interface:

var IHandler = new(http.Handler)

container, err := inject.New(
    inject.Provide(NewServeMux, inject.As(IHandler)),
    inject.Provide(NewServer),
)

var handler http.Handler
container.Extract(&handler) // *http.ServeMux will be extracted

var server *http.Server
container.Extract(&server) // server.Handler is *http.ServeMux

Bundles

// ProcessingBundle responsible for processing
var ProcessingBundle = inject.Bundle(
    inject.Provide(processing.NewDispatcher),
    inject.Provide(processing.NewProvider),
    inject.Provide(processing.NewProxy, inject.As(IProxy)),
)

// BillingBundle responsible for billing
var BillingBundle = inject.Bundle(
    inject.Provide(billing.NewInteractor),
    inject.Provide(billing.NewInvoiceRepository, inject.As(new(InvoiceRepository)))
)

And test each one separately.

func TestProcessingBundle(t *testing.T) {
    bundle, err := inject.New(
        ProcessingBundle,
        inject.Replace(processing.NewDevProxy, inject.As(IProxy)),
    )
    
    var dispatcher *processing.Dispatcher
    container.Extract(&dispatcher)
    
    dispatcher.Dispatch(ctx context.Context, thing)
}

Replace

var options []inject.Options

if os.Getenv("ENV") == "dev" {
    options = append(options, inject.Replace(billing.NewInvoiceRepositoryMock), inject.As(new(InvoiceRepository)))
}

container, err := inject.New(options...)

Named definitions

container, err := inject.New{
	inject.Provide(NewDefaultServer, inject.WithName("default")),
	inject.Provide(NewAdminServer, inject.WithName("admin")),
}

var defaultServer *http.Server
var adminServer *http.Server

container.Extract(&defaultServer, inject.Name("default"))
container.Extract(&adminServer, inject.Name("admin"))

Or with struct provider:

// Application
type Application struct {
    Server *http.Server `inject:"default"`
    AdminServer *http.Server `inject:"admin"`
}
container, err := inject.New(
    inject.Provide(NewDefaultServer, inject.WithName("default")), 
    inject.Provide(NewAdminServer, inject.WithName("admin")),
    inject.Provide(&Application)
)

If you don't like tags as much as I do, then look to inject.Exported() provide option.

Use combined provider

For advanced providing use combined provider. It's both - struct and constructor providers.

// ServerProvider
type ServerProvider struct {
	Mux *http.Server `inject:"dude_mux"`
}

// Provide is a container predefined constructor function for *http.Server.
func (p *ServerProvider) Provide() *http.Server {
	return &http.Server{
		Handler: p.Mux,
	}
}

Visualize (Graphviz)

Write visualization into io.Writer. Check out result on graphviz online tool!

    // visualization data target
    buffer := &bytes.Buffer{}
    
    // write container visualization
    container.WriteTo(buffer)

or

    // define github.com/emicklei/*dot.Graph type
    var graph *dot.Graph
    
    // extract graph
    container.Extract(&graph)

    // use
    graph.Write(buffer)
    

This is visualization of container example.

FAQs

Last updated on 25 Nov 2019

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc