sting

package module
Version: v0.0.0-...-d7e01fc Latest Latest
Warning

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

Go to latest
Published: Oct 3, 2017 License: BSD-3-Clause Imports: 9 Imported by: 0

README

Sting

Current Version: 1.0.0

Sting is a lightweight dependency injection for go. It uses reflection to build a di container and to resolve dependencies. Therefore it comes with a performance penalty in comparsion to a non sting based application.

GoDoc Go Report Card

Table of content

Features

  • Easy service registration
  • No complex configuration needed
  • No external dependencies
  • Supports named services
  • Supports sub containers
  • Supports function and struct injection
  • Supports resolving services by name, interface and struct
  • Supports http.Handler injection by using a sting.HandlerFunc
  • Provides three different service lifetimes (transient, request, container)
  • Supports custom lifetimes

Usage

Supported Types

The following types are supported for service registration and resolving:

  • struct
  • pointer to struct
  • interface
Register Services

Create a builder and register services, afterwards a call to Build builds the dependency graph and verifies that no cycles or lifetime violation exists. To register a service use builder.Register or builder.RegisterNamed, the latter one register a service with a name, this is useful if one wants to register the same type more then once.

package main

import (
    "fmt"

    "bitbucket.org/snmed/sting"
)

type UsefulStruct struct { msg string }
type UsefulInterface interface {
    Say()
}

func (u UsefulStruct) Say() {
    fmt.Println(u.msg)
}

func main(){
    // Register services and build container at once
    container, err := sting.NewBuilder().
        Register(UsefulStruct{"Very useful"}, sting.TransientScope()).
        Register( // A creator function
            func(u UsefulStruct) (UsefulInterface, error) {
                // Do some useful initialisation work here
                 return u,nil },
            sting.ContainerScope(),
        ).
        RegisterNamed("alsoUseful",&UsefulStruct{"More useful"}, sting.TransientScope()).
        Build()

        svc, _, err := container.GetService((*UsefulInterface)(nil))

        if err == nil {
            svc.(*UsefulInterface).Say()
        }

}

If a creator function is used, it must be in form of:

// creatorFunc
func([arg type]*) (type, error) { /* Do some initialisation work */ }

The creator function can have zero or more arguments of a supported type. This dependencies will be resolved while building the di container and returns an error if a required item is not registered. The builder deduces the type that will be created by the creator function and register it. As for the arguments, the first return parameter must be of a supported type.

Register

Input:

  1. ARG1 := creatorFunc | struct | *struct service to register.
  2. ARG2 := sting.Scope a lifetime scope to use for this service.

Output:

  1. RET := sting.Builder the used Builder, to support fluent registration of services.
// Signature
builder.Register(interface{}, Scope) Builder
// Example
builder.Register(UsefulStruct{msg: "Very Useful"}, sting.TransientScope())
RegisterNamed

Input:

  1. ARG1 := string the name under which the service will be registered.
  2. ARG2 := creatorFunc | struct | *struct service to register.
  3. ARG3 := sting.Scope a lifetime scope to use for this service.

Output:

  1. RET := sting.Builder the used Builder, to support fluent registration of services.
// Signature
builder.RegisterNamed(string, interface{}, Scope) Builder
// Example
builder.RegisterNamed("MyUswfulService", UsefulStruct{msg: "Very Useful"}, sting.TransientScope())
Retrieve Services

To retrieve a service use GetService, Inject or HandlerFunc. Each of these function has a different use case as described in the following paragraphs.

GetService

Input:

  1. ARG1 := (*interface)(nil) | (*struct)(nil) | string nil pointer to a service type or a string for a named service.
  2. ARG2 := context.Context context to use for request scoped services.

Returns:

  1. RET1 := interface{} | nil returns the requested service or nil.
  2. RET2 := context.Context returns a context for request scoped services. Further calls to Inject or GetService should use this context
  3. RET3 := error returns an error if a service is not found or could not be created, as well as when an invalid type is passed to ARG1.
// Signature
container.GetService(interface{}, ...context.Context) (interface{}, context.Context, error)
// Example
svc, ctx, err := container.GetService((*UsefulInterface)(nil), someContext)

GetService takes at least one argument of type (*interface)(nil), (*struct)(nil) or a string and one optional argument of type context.Context. If more than one context is passed, only the first one is used all other contexts will be ignored. Context is only required if a request scope is used and therefore it is necessary to pass the returned context to any further call to GetService or Inject within related requests. This is the most straight forward way to get a single service and returns always a pointer to struct or a interface.

Inject

Input:

  1. ARG1 := *struct | func([arg type]*) a pointer to struct or a function into which the dependencies will be injected.
  2. ARG2 := context.Context context to use for request scoped services.

Returns:

  1. RET1 := context.Context returns a context for request scoped services. Further calls to Inject or GetService should use this context
  2. RET2 := error returns an error if a service is not found or could not be created, as well as when an invalid type is passed to ARG1.
// Signature
container.Inject(interface{}, ...context.Context) (context.Context, error)
// Example with stuct
svc, ctx, err := container.Inject(&myController{}, someContext)
// Example with a function 
svc, ctx, err := container.Inject(func(cfg Config, repo Repository, log *Logger) { /* Do something with the dependencies */ }, someContext)

Inject takes a pointer to struct or a function as first argument and an optional second argument of type context.Context. As for GetService only the first context is used. A function can have as many argument as it needs, but all of them must be registered within the di container, otherwise an error is returned. Arguments must be of a supported type. If a pointer to struct is used as first argument, the di container tries to resolve every supported type defined in that struct and inject the services into it. The following tags can be used to change the behavior of the di container:

type target struct {
    repo PersonRepository `di:"ignore"` // This field will be ignored, must be specified for every struct, *struct and interface which should not be resolved.
    Cfg Config `di:"name=myconfig"` // This field wants a named service of type Config.
    msg string `di:"func=SetMessage"` // This field has a setter with a dependecy, the di container calls the setter with all required arguments (must be registered)
}

If a struct has unexported fields of supported types, the di container tries to find a setter function like Set<UpperCaseFieldName> and tries to inject it, otherwise Inject returns an error. It is possible to combine the two tags name and func to use a named service together with a setter function. Setter functions must have one argument of a supported type, the di container deduces the required dependency according the setters argument type. For example SetMessage(c Config) looks for a service of type Config, if not found an error is returned.

Inject accepts also functions in form of

func([arg type]*) { /* use dependency */ }

it can have one or more arguments with a supported type.

HandlerFunc

Input:

  1. ARG1 := InjectionHandler a http.HandlerFunc with additional arguments of a supported type.

Returns:

  1. RET1 := http.Handler returns http.Handler, panics if a dependency is missing, an invalid type as argument passed or an error occured while creating a dependency.
// Signature
container.HandlerFunc(handler InjectionHandler) http.Handler
// Example
container.HandlerFunc(func(w http.ResponseWriter, r *http.Request, repo PersonRepository, pers Person){ /* Do something useful */ })

HandlerFunc takes an InjectionHandler as argument and returns a http.Handler. It can be used to inject dependencies into a function which serves http requests. It's not necessary to pass any context to use a request scope.

Creating a child builder

If a use case requires the same type of dependencies more than once and a named service is not an option, then creating a child builder is a possible solution.

// Signature
builder.NewBuilder() Builder
// Example
builder.Register(Person{}, sting.TransientScope()
childBuilder.Register(Person{}, sting.TransientScope()

container, perr := builder.Build()
subcontainer, serr := childBuilder.Build()

NewBuilder returns a new Builder with no registered services. If a child Builder can't find a dependecies, it will call GetService on the parent Builder to obtain a service. Caveat: A child builder must be built before his parent, otherwise Build returns with an error. This is necessary for checking missing dependencies and lifetime violations.

License

BSD-3-Clause

Documentation

Overview

Package sting provides a simple and lightweigtht dependency injection for go.

See project overview for more information: https://bitbucket.org/snmed/sting/overview

Example

This file contains only prerequisites for all other examples. This is necessary because of the behavior of godoc. If an example has any type or function definition in it, godoc does not show a separate block for the output of the example.

package main

import (
	"fmt"
	"log"
	"net/http"
	"strconv"

	"bitbucket.org/snmed/sting"
)

type (
	PersonRepository interface {
		Find(int) *Person
		FindByName(string) *Person
	}

	PersonAccess struct {
		name string
		id   int
	}

	Config struct {
		DefaultName string
		DefaultId   int
	}

	Person struct {
		Id   int
		Name string
	}

	Log struct {
		logger log.Logger
	}
)

func (p PersonAccess) Find(id int) *Person {
	return &Person{Name: p.name, Id: id}
}

func (p PersonAccess) FindByName(name string) *Person {
	return &Person{Name: name, Id: p.id}
}

func (l *Log) Info(msg string) {
	l.logger.Println(fmt.Sprintf("Info: %v", msg))
}

func (l *Log) Error(msg string) {
	l.logger.Println(fmt.Sprintf("Error: %v", msg))
}

func createMyConfig() (*Config, error) {
	return &Config{DefaultId: 11, DefaultName: "Selene"}, nil
}

type Controller struct {
	config   *Config
	MyConfig Config           `di:"name=myconfig"`
	ignored  PersonRepository `di:"ignore"`
	repo     PersonRepository `di:"func=SetRepo"`
	Access   PersonAccess     `di:"func=SetPersonAccess,name=myconfig"`
}

func (c *Controller) SetConfig(cfg *Config) {
	c.config = cfg
}

func (c *Controller) SetRepo(r PersonRepository) {
	c.repo = r
}

func (c *Controller) SetPersonAccess(cfg Config) {
	c.Access = PersonAccess{id: cfg.DefaultId, name: cfg.DefaultName}
}

func LogMiddleware(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Do some useful logging
		fmt.Printf("Calling URL %v with method %v ...\n", r.URL, r.Method)
		handler.ServeHTTP(w, r)
	})
}

func FindPerson(w http.ResponseWriter, r *http.Request, repo PersonRepository, pers Person) {
	if id, err := strconv.Atoi(r.FormValue("id")); err == nil {
		w.Write([]byte(fmt.Sprintf("%v", repo.Find(id))))
	} else {
		w.Write([]byte(fmt.Sprintf("%v", pers)))
	}
}

func ChangeCfgMiddleware(c sting.Container, handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// If GetService or Inject is used inside a handler func, it's
		// necessary to pass the request context to those functions.
		cfg, _, _ := c.GetService((*Config)(nil), r.Context())
		cfg.(*Config).DefaultName = "Pumuckel"
		handler.ServeHTTP(w, r)
	})
}

// This file contains only prerequisites for all other examples. This is
// necessary because of the behavior of godoc. If an example has any
// type or function definition in it, godoc does not show a separate block
// for the output of the example.
func main() {
	// This file contains only prerequisites for all other examples.
}
Output:

Example (GetService)

This example shows how to register multiple services with the same type and how to retrieve services from the di container.

container, err := sting.NewBuilder().
	// Register a pointer to struct with a  container scope
	Register(&Config{DefaultId: 42, DefaultName: "Judge Dredd"}, sting.ContainerScope()).
	// Register a creator function with a dependency and container scope
	Register(
		func(c Config) (PersonRepository, error) {
			return PersonAccess{id: c.DefaultId, name: c.DefaultName}, nil
		},
		sting.RequestScope(),
	).
	// Register a named service with an already registered type
	RegisterNamed(
		"myconfig",
		func() (*Config, error) { return &Config{DefaultId: 11, DefaultName: "Selene"}, nil },
		sting.RequestScope(),
	).
	Build()

if err != nil {
	log.Fatalln(err)
}

//Get a service by passing a nil pointer to an interface
svc, _, err := container.GetService((*PersonRepository)(nil))
if err != nil {
	log.Fatalln(err)
}

// Get a service by passing a nil pointer to a struct
cfg, _, err := container.GetService((*Config)(nil))
if err != nil {
	log.Fatalln(err)
}

// Get a named service
mycfg, ctx, err := container.GetService("myconfig")
if err != nil {
	log.Fatalln(err)
}

// Change values
mycfg.(*Config).DefaultName = "Tom Bombadil"
mycfg.(*Config).DefaultId = 9999

// Get the same named service by passing the context
cfg2, _, err := container.GetService("myconfig", ctx)
if err != nil {
	log.Fatalln(err)
}

// Get the named service without a context, same as a new request.
cfg3, _, err := container.GetService("myconfig")
if err != nil {
	log.Fatalln(err)
}

fmt.Println(svc.(PersonRepository).Find(42))
fmt.Println(cfg)
fmt.Println(mycfg)
fmt.Println(cfg2)
fmt.Println(cfg3)
Output:

&{42 Judge Dredd}
&{Judge Dredd 42}
&{Tom Bombadil 9999}
&{Tom Bombadil 9999}
&{Selene 11}
Example (HandlerFunc)

This example shows how to use the di container in a web application or a microservice. Wrap any InjectionHandler inside a container.HandlerFunc. A InjectionHandler is in form of a http.Handler, but can have as many additional arguments as needed, as far as the argument types are one of the supported di types.

container, err := sting.NewBuilder().
	// Register a pointer to struct with a  container scope
	Register(&Config{DefaultId: 42, DefaultName: "Judge Dredd"}, sting.RequestScope()).
	// Register a creator function with a dependency and container scope
	Register(
		func(c Config) (PersonRepository, error) {
			return PersonAccess{id: c.DefaultId, name: c.DefaultName}, nil
		},
		sting.RequestScope(),
	).
	// Register a named service with an already registered type
	Register(
		func() (*Person, error) { return &Person{Id: 11, Name: "Selene"}, nil },
		sting.RequestScope(),
	).
	Build()

if err != nil {
	log.Fatalln(err)
}

handler := ChangeCfgMiddleware(container, container.HandlerFunc(FindPerson))
handler = LogMiddleware(handler)

recorder := httptest.NewRecorder()
handler.ServeHTTP(recorder, httptest.NewRequest("GET", "/api?id=55", nil))

fmt.Println(recorder.Body)

recorder = httptest.NewRecorder()
handler.ServeHTTP(recorder, httptest.NewRequest("GET", "/api", nil))

fmt.Println(recorder.Body)
Output:

Calling URL /api?id=55 with method GET ...
&{55 Pumuckel}
Calling URL /api with method GET ...
{11 Selene}
Example (Inject)

This example shows how to inject dependencies into structs and functions.

container, err := sting.NewBuilder().
	// Register a pointer to struct with a  container scope
	Register(Config{DefaultId: 42, DefaultName: "Judge Dredd"}, sting.ContainerScope()).
	// Register a creator function with a dependency and container scope
	Register(
		func(c Config) (PersonRepository, error) {
			return PersonAccess{id: c.DefaultId, name: c.DefaultName}, nil
		},
		sting.RequestScope(),
	).
	// Register a named service with an already registered type
	RegisterNamed(
		"myconfig",
		func() (*Config, error) { return &Config{DefaultId: 11, DefaultName: "Selene"}, nil },
		sting.RequestScope(),
	).
	Build()

controller := &Controller{}

// Inject dependencies into a struct
_, err = container.Inject(controller)
if err != nil {
	log.Fatalln(err)
}

var config *Config
var repo PersonRepository

// Inject dependencies into a function
container.Inject(func(c *Config, r PersonRepository) {
	config = c
	config.DefaultId += c.DefaultId
	config.DefaultName += " changed"
	repo = r
})

fmt.Println(controller.config)
fmt.Println(controller.MyConfig)
fmt.Println(controller.ignored)
fmt.Println(controller.repo)
fmt.Println(controller.Access)
fmt.Println(config)
fmt.Println(repo)
Output:

&{Judge Dredd 42}
{Selene 11}
<nil>
{Judge Dredd 42}
{Selene 11}
&{Judge Dredd changed 84}
{Judge Dredd 42}
Example (Register)

This example shows how to register services and dependencies. Register requires as first argument a struct, pointer to struct or a creator function and as second argument a scope.

RegisterNamed requires as first argument a string under which the service will be registered, the other two arguments are the same as for the Register function.

container, err := sting.NewBuilder().
	// Register a struct with a transient scope
	Register(Log{}, sting.TransientScope()).
	// Register a pointer to struct with a  container scope
	Register(&Config{DefaultId: 42, DefaultName: "Judge Dredd"}, sting.ContainerScope()).
	// Register a creator function with a dependency and container scope
	Register(
		func(c Config) (PersonRepository, error) {
			return PersonAccess{id: c.DefaultId, name: c.DefaultName}, nil
		},
		sting.ContainerScope(),
	).
	// Register a named service with an already registered type
	RegisterNamed(
		"myconfig",
		createMyConfig,
		sting.RequestScope(),
	).
	Build()

if err != nil {
	log.Fatalln(err)
}

// Get a service by passing a nil pointer to an interface
svc, _, err := container.GetService((*PersonRepository)(nil))
if err != nil {
	log.Fatalln(err)
}

fmt.Println(svc.(PersonRepository).Find(42))
Output:

&{42 Judge Dredd}
Example (SubContainer)

This example shows how to use the di container in a web application or a microservice. If request scope is used, wrap first handler of a handler chain within the UseHTTPRequestContext middleware. Afterwards wrap any InjectionHandler inside a container.HandlerFunc.

// Create the first builder and register services
builder := sting.NewBuilder().
	Register(&Config{DefaultId: 42, DefaultName: "Judge Dredd"}, sting.TransientScope()).
	Register(
		func(c Config) (PersonRepository, error) {
			return PersonAccess{id: c.DefaultId, name: c.DefaultName}, nil
		},
		sting.RequestScope(),
	).
	Register(
		func() (*Person, error) { return &Person{Id: 11, Name: "Selene"}, nil },
		sting.RequestScope(),
	)

// Create a child builder and register services
childBuilder := builder.NewBuilder().
	Register(
		func(c Config) (PersonRepository, error) {
			return PersonAccess{id: 2 * c.DefaultId, name: "Child " + c.DefaultName}, nil
		},
		sting.ContainerScope(),
	)

// Important build parent builder first
container, perr := builder.Build()
subcontainer, serr := childBuilder.Build()

if perr != nil || serr != nil {
	log.Fatalln(perr, serr)
}

// Now use containers in handler chains
parentHandler := LogMiddleware(container.HandlerFunc(FindPerson))
subHandler := LogMiddleware(subcontainer.HandlerFunc(FindPerson))

precorder := httptest.NewRecorder()
parentHandler.ServeHTTP(precorder, httptest.NewRequest("GET", "/api?id=55", nil))

fmt.Println(precorder.Body)

precorder = httptest.NewRecorder()
parentHandler.ServeHTTP(precorder, httptest.NewRequest("GET", "/api", nil))

fmt.Println(precorder.Body)

srecorder := httptest.NewRecorder()
subHandler.ServeHTTP(srecorder, httptest.NewRequest("GET", "/api?id=55", nil))

fmt.Println(srecorder.Body)

srecorder = httptest.NewRecorder()
subHandler.ServeHTTP(srecorder, httptest.NewRequest("GET", "/api", nil))

fmt.Println(srecorder.Body)
Output:

Calling URL /api?id=55 with method GET ...
&{55 Judge Dredd}
Calling URL /api with method GET ...
{11 Selene}
Calling URL /api?id=55 with method GET ...
&{55 Child Judge Dredd}
Calling URL /api with method GET ...
{11 Selene}

Index

Examples

Constants

View Source
const VERSION = "1.0.0"

VERSION is the current sting version

Variables

This section is empty.

Functions

func DefaultScopeLifeTimeFunc

func DefaultScopeLifeTimeFunc(s Scope) int

DefaultScopeLifeTimeFunc is the default ScopeLifeTimeFunc for a Builder instance.

func IsActionFuncReturnedNil

func IsActionFuncReturnedNil(e error) bool

IsActionFuncReturnedNil checks if an error is caused by an action function which returns nil.

func IsContainerAlreadyBuilt

func IsContainerAlreadyBuilt(e error) bool

IsContainerAlreadyBuilt checks if an error is caused by registering a service on an already built container.

func IsCycleDetected

func IsCycleDetected(e error) bool

IsCycleDetected checks if an error is caused by a cycle in the dependency graph.

func IsInvalidCreatorFunc

func IsInvalidCreatorFunc(e error) bool

IsInvalidCreatorFunc checks if an error is caused by an invalid creator function.

func IsInvalidInjectionHandler

func IsInvalidInjectionHandler(e error) bool

IsInvalidInjectionHandler checks if an error is caused by an invalid injection handler.

func IsInvalidInjectionTarget

func IsInvalidInjectionTarget(e error) bool

IsInvalidInjectionTarget checks if an error is caused by a call to Inject with an invalid target.

func IsInvalidServiceRequest

func IsInvalidServiceRequest(e error) bool

IsInvalidServiceRequest checks if an error is caused by a call to GetService with an invalid argument.

func IsLifetimeViolation

func IsLifetimeViolation(e error) bool

IsLifetimeViolation checks if an error is caused by a lifetime violation.

func IsMissingDependency

func IsMissingDependency(e error) bool

IsMissingDependency checks if an error is caused by a missing dependency.

func IsParentContainerNotBuilt

func IsParentContainerNotBuilt(e error) bool

IsParentContainerNotBuilt checks if an error is caused by calling Build on sub container with a not build parent container.

func IsServiceAlreadyRegistered

func IsServiceAlreadyRegistered(e error) bool

IsServiceAlreadyRegistered checks if an error is caused by registering a service twice.

func IsServiceNotFound

func IsServiceNotFound(e error) bool

IsServiceNotFound checks if an error is caused by a unresolved dependency.

func IsUnexpectedError

func IsUnexpectedError(e error) bool

IsUnexpectedError checks if an error is an unexpected error.

Types

type ActionFunc

type ActionFunc func(ctx context.Context) (interface{}, error)

ActionFunc executes initialisation work and returns an instance of a dependency object.

type Builder

type Builder interface {
	// Register registers a creator function and deduces its service name with
	// reflection from the first output parameter of the creator function. A creator
	// function has the form:
	//
	//	func((arg type)*) (type, error) { /* construct return type */ }
	//
	// The function can have zero or more arguments, but only two return types whereby the
	// last one must be the error interface. The 'type' must be one of struct, pointer to struct or
	// interface. It's also possible to register a struct or pointer to struct directly, see examples
	// for more information. Caveat: It is not possible to register a pointer to struct and a struct
	// of the same type, this might be changed in a future release.
	Register(interface{}, Scope) Builder
	// RegisterNamed registers a given creator function with a specified name and scope.
	// It's possible to register the same type with different names. Also it's possible to register
	// a type that is already registered with the 'Register' function. It's also possible
	// to register a struct or pointer to struct directly, see examples for more information.
	RegisterNamed(string, interface{}, Scope) Builder
	// Build builds and verifies all registered services. It returns an error if any of
	// this cases occurs:
	//
	//  - Invalid creator function passed
	//  - Service already registered
	//  - Missing dependency for creator function
	//  - Container already built
	//  - Parent container not built
	//  - If creator function uses dependency with a lower life time level
	Build() (Container, error)

	// NewBuilder returns a new child builder, so you can overwrite some
	// dependencies in its parent builder or register additional dependencies.
	// It is necesseray to build a parent container first, before building the child
	// container. The child container lookup dependencies first in its own registry,
	// if it can't find a requested service or dependency, it will ask its parent container
	// for any missing item by calling GetService on it.
	NewBuilder() Builder
}

The Builder interface is responsible to register dependencies and to build the di container.

func NewBuilder

func NewBuilder(c ...Configure) Builder

NewBuilder returns a preconfigured Builder ready to use.

type Configure

type Configure func(*Options)

Configure changes options of the Builder instance.

func UseLifeTimeCheck

func UseLifeTimeCheck(b bool) Configure

UseLifeTimeCheck enables or disables lifetime checks during container build process.

func UseScopeLifeTimeFunc

func UseScopeLifeTimeFunc(fn ScopeLifeTimeFunc) Configure

UseScopeLifeTimeFunc configures the Builder to use the supplied function to check life time violations. This is useful if a custom scope is used and overwrites the default life time function.

type Container

type Container interface {
	// ID returns the unique identifier for this Container.
	ID() ContainerID
	// Injects dependencies into a struct or function, accepts pointer to struct and functions.
	// Request scope needs a context as second argument, otherwise it works like a transient scope.
	// Only the first context arguemnt is used, all additional passed contexts will be ignored.
	Inject(interface{}, ...context.Context) (context.Context, error)
	// Gets a service, accepts only pointer to interface with a nil value ex. (*io.Closer)(nil),
	// pointer to struct or a string for a named service. It returns the interface or a pointer to a struct.
	// Request scope needs a context as second argument, otherwise it works like a transient scope.
	// Only the first context arguemnt is used, all additional passed contexts will be ignored.
	GetService(interface{}, ...context.Context) (interface{}, context.Context, error)
	// Injects all dependencies into a InjectionHandler. Returns a http.Handler.
	// Panics if any dependency is missing in the container.
	// Request scope requires the use of the UseHTTPRequestContext middleware.
	HandlerFunc(InjectionHandler) http.Handler
}

Container is responsible to resolve, construct and inject dependencies.

type ContainerID

type ContainerID string

ContainerID is an unique container identifier which differs for every container.

type InjectionHandler

type InjectionHandler interface{}

InjectionHandler is a HandlerFunc with an arbitrary amount of additional parameters. All additional parameters must be of type struct, pointer to struct or interface. InjectionHandler must be a function in form of:

func(http.ResponseWriter, *http.Request, [additional parameters...] )

type Options

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

Options is used to configure the Builder instance.

type Scope

type Scope interface {
	Get(context.Context, interface{}, ActionFunc) (interface{}, error)
}

Scope provides a storage for dependency objects and manages their lifetime.

func ContainerScope

func ContainerScope() Scope

ContainerScope executes on first call the ActionFunc and returns the same instance for all subsequent calls.

func RequestScope

func RequestScope() Scope

RequestScope executes on first call the ActionFunc and returns for all subsequent calls in the same request the created instance.

func TransientScope

func TransientScope() Scope

TransientScope executes the ActionFunc for each call and returns the created instance.

type ScopeLifeTimeFunc

type ScopeLifeTimeFunc func(Scope) int

ScopeLifeTimeFunc returns the life time level of a scope. Dependencies defined within a certain level must not have any dependencies defined in a higher level.

Directories

Path Synopsis
gen

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to