Logo

0x3d.Site

is designed for aggregating information.
Welcome
check repository here

do - Dependency Injection

tag Go Version GoDoc Build Status Go report Coverage License

⚙️ A dependency injection toolkit based on Go 1.18+ Generics.

This library implements the Dependency Injection design pattern. It may replace the uber/dig fantastic package in simple Go projects. samber/do uses Go 1.18+ generics and therefore offers a typesafe API.

See also:

  • samber/lo: A Lodash-style Go library based on Go 1.18+ Generics
  • samber/mo: Monads based on Go 1.18+ Generics (Option, Result, Either...)

Why this name?

I love short name for such a utility library. This name is the sum of DI and Go and no Go package currently uses this name.

⭕⭕⭕⭕⭕⭕ About v2 ⭕⭕⭕⭕⭕⭕

Check out the beta now!

go get -u github.com/samber/do/[email protected]

Documentation: https://do.samber.dev/

Please report bugs here: #45.

💡 Features

  • Service registration
  • Service invocation
  • Service health check
  • Service shutdown
  • Service lifecycle hooks
  • Named or anonymous services
  • Eagerly or lazily loaded services
  • Dependency graph resolution
  • Default injector
  • Injector cloning
  • Service override
  • Lightweight, no dependencies
  • No code generation

🚀 Services are loaded in invocation order.

🕵️ Service health can be checked individually or globally. Services implementing do.Healthcheckable interface will be called via do.HealthCheck[type]() or injector.HealthCheck().

🛑 Services can be shutdowned properly, in back-initialization order. Services implementing do.Shutdownable interface will be called via do.Shutdown[type]() or injector.Shutdown().

🚀 Install

go get github.com/samber/do@v1

This library is v1 and follows SemVer strictly.

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

This library has no dependencies except the Go std lib.

💡 Quick start

You can import do using:

import (
    "github.com/samber/do"
)

Then instantiate services:

func main() {
    injector := do.New()

    // provides CarService
    do.Provide(injector, NewCarService)

    // provides EngineService
    do.Provide(injector, NewEngineService)

    car := do.MustInvoke[*CarService](https://raw.githubusercontent.com/samber/do/master/injector)
    car.Start()
    // prints "car starting"

    do.HealthCheck[EngineService](https://raw.githubusercontent.com/samber/do/master/injector)
    // returns "engine broken"

    // injector.ShutdownOnSIGTERM()    // will block until receiving sigterm signal
    injector.Shutdown()
    // prints "car stopped"
}

Services:

type EngineService interface{}

func NewEngineService(i *do.Injector) (EngineService, error) {
    return &engineServiceImplem{}, nil
}

type engineServiceImplem struct {}

// [Optional] Implements do.Healthcheckable.
func (c *engineServiceImplem) HealthCheck() error {
	return fmt.Errorf("engine broken")
}
func NewCarService(i *do.Injector) (*CarService, error) {
    engine := do.MustInvoke[EngineService](https://raw.githubusercontent.com/samber/do/master/i)
    car := CarService{Engine: engine}
    return &car, nil
}

type CarService struct {
	Engine EngineService
}

func (c *CarService) Start() {
	println("car starting")
}

// [Optional] Implements do.Shutdownable.
func (c *CarService) Shutdown() error {
	println("car stopped")
	return nil
}

🤠 Spec

GoDoc: https://godoc.org/github.com/samber/do

Injector:

Service registration:

Service invocation:

Service override:

Injector (DI container)

Build a container for your components. Injector is responsible for building services in the right order, and managing service lifecycle.

injector := do.New()

Or use nil as the default injector:

do.Provide(nil, func (i *Injector) (int, error) {
    return 42, nil
})

service := do.MustInvoke[int](https://raw.githubusercontent.com/samber/do/master/nil)

You can check health of services implementing func HealthCheck() error.

type DBService struct {
    db *sql.DB
}

func (s *DBService) HealthCheck() error {
    return s.db.Ping()
}

injector := do.New()
do.Provide(injector, ...)
do.Invoke(injector, ...)

statuses := injector.HealthCheck()
// map[string]error{
//   "*DBService": nil,
// }

De-initialize all compoments properly. Services implementing func Shutdown() error will be called synchronously in back-initialization order.

type DBService struct {
    db *sql.DB
}

func (s *DBService) Shutdown() error {
    return s.db.Close()
}

injector := do.New()
do.Provide(injector, ...)
do.Invoke(injector, ...)

// shutdown all services in reverse order
injector.Shutdown()

List services:

type DBService struct {
    db *sql.DB
}

injector := do.New()

do.Provide(injector, ...)
println(do.ListProvidedServices())
// output: []string{"*DBService"}

do.Invoke(injector, ...)
println(do.ListInvokedServices())
// output: []string{"*DBService"}

Service registration

Services can be registered in multiple way:

  • with implicit name (struct or interface name)
  • with explicit name
  • eagerly
  • lazily

Anonymous service, loaded lazily:

type DBService struct {
    db *sql.DB
}

do.Provide[DBService](https://raw.githubusercontent.com/samber/do/master/injector, func(i *Injector) (*DBService, error) {
    db, err := sql.Open(...)
    if err != nil {
        return nil, err
    }

    return &DBService{db: db}, nil
})

Named service, loaded lazily:

type DBService struct {
    db *sql.DB
}

do.ProvideNamed(injector, "dbconn", func(i *Injector) (*DBService, error) {
    db, err := sql.Open(...)
    if err != nil {
        return nil, err
    }

    return &DBService{db: db}, nil
})

Anonymous service, loaded eagerly:

type Config struct {
    uri string
}

do.ProvideValue[Config](https://raw.githubusercontent.com/samber/do/master/injector, Config{uri: "postgres://user:pass@host:5432/db"})

Named service, loaded eagerly:

type Config struct {
    uri string
}

do.ProvideNamedValue(injector, "configuration", Config{uri: "postgres://user:pass@host:5432/db"})

Service invocation

Loads anonymous service:

type DBService struct {
    db *sql.DB
}

dbService, err := do.Invoke[DBService](https://raw.githubusercontent.com/samber/do/master/injector)

Loads anonymous service or panics if service was not registered:

type DBService struct {
    db *sql.DB
}

dbService := do.MustInvoke[DBService](https://raw.githubusercontent.com/samber/do/master/injector)

Loads named service:

config, err := do.InvokeNamed[Config](https://raw.githubusercontent.com/samber/do/master/injector, "configuration")

Loads named service or panics if service was not registered:

config := do.MustInvokeNamed[Config](https://raw.githubusercontent.com/samber/do/master/injector, "configuration")

Individual service healthcheck

Check health of anonymous service:

type DBService struct {
    db *sql.DB
}

dbService, err := do.Invoke[DBService](https://raw.githubusercontent.com/samber/do/master/injector)
err = do.HealthCheck[DBService](https://raw.githubusercontent.com/samber/do/master/injector)

Check health of named service:

config, err := do.InvokeNamed[Config](https://raw.githubusercontent.com/samber/do/master/injector, "configuration")
err = do.HealthCheckNamed(injector, "configuration")

Individual service shutdown

Unloads anonymous service:

type DBService struct {
    db *sql.DB
}

dbService, err := do.Invoke[DBService](https://raw.githubusercontent.com/samber/do/master/injector)
err = do.Shutdown[DBService](https://raw.githubusercontent.com/samber/do/master/injector)

Unloads anonymous service or panics if service was not registered:

type DBService struct {
    db *sql.DB
}

dbService := do.MustInvoke[DBService](https://raw.githubusercontent.com/samber/do/master/injector)
do.MustShutdown[DBService](https://raw.githubusercontent.com/samber/do/master/injector)

Unloads named service:

config, err := do.InvokeNamed[Config](https://raw.githubusercontent.com/samber/do/master/injector, "configuration")
err = do.ShutdownNamed(injector, "configuration")

Unloads named service or panics if service was not registered:

config := do.MustInvokeNamed[Config](https://raw.githubusercontent.com/samber/do/master/injector, "configuration")
do.MustShutdownNamed(injector, "configuration")

Service override

By default, providing a service twice will panic. Service can be replaced at runtime using do.Override helper.

do.Provide[Vehicle](https://raw.githubusercontent.com/samber/do/master/injector, func (i *do.Injector) (Vehicle, error) {
    return &CarImplem{}, nil
})

do.Override[Vehicle](https://raw.githubusercontent.com/samber/do/master/injector, func (i *do.Injector) (Vehicle, error) {
    return &BusImplem{}, nil
})

Hooks

2 lifecycle hooks are available in Injectors:

  • After registration
  • After shutdown
injector := do.NewWithOpts(&do.InjectorOpts{
    HookAfterRegistration: func(injector *do.Injector, serviceName string) {
        fmt.Printf("Service registered: %s\n", serviceName)
    },
    HookAfterShutdown: func(injector *do.Injector, serviceName string) {
        fmt.Printf("Service stopped: %s\n", serviceName)
    },

    Logf: func(format string, args ...any) {
        log.Printf(format, args...)
    },
})

Cloning injector

Cloned injector have same service registrations as it's parent, but it doesn't share invoked service state.

Clones are useful for unit testing by replacing some services to mocks.

var injector *do.Injector;

func init() {
    do.Provide[Service](https://raw.githubusercontent.com/samber/do/master/injector, func (i *do.Injector) (Service, error) {
        return &RealService{}, nil
    })
    do.Provide[*App](https://raw.githubusercontent.com/samber/do/master/injector, func (i *do.Injector) (*App, error) {
        return &App{i.MustInvoke[Service](https://raw.githubusercontent.com/samber/do/master/i)}, nil
    })
}

func TestService(t *testing.T) {
    i := injector.Clone()
    defer i.Shutdown()

    // replace Service to MockService
    do.Override[Service](https://raw.githubusercontent.com/samber/do/master/i, func (i *do.Injector) (Service, error) {
        return &MockService{}, nil
    }))

    app := do.Invoke[*App](https://raw.githubusercontent.com/samber/do/master/i)
    // do unit testing with mocked service
}

🛩 Benchmark

// @TODO

🤝 Contributing

Don't hesitate ;)

With Docker

docker-compose run --rm dev

Without Docker

# Install some dev dependencies
make tools

# Run tests
make test
# or
make watch-test

👤 Contributors

Contributors

💫 Show your support

Give a ⭐️ if this project helped you!

GitHub Sponsors

📝 License

Copyright © 2022 Samuel Berthe.

This project is MIT licensed.

Golang
Golang
Golang, or Go, is a statically typed programming language developed by Google. It’s known for its simplicity, performance, and support for concurrent programming. Go is widely used in cloud computing, server-side applications, and microservices.
GitHub - goyek/goyek: Task automation Go library
GitHub - goyek/goyek: Task automation Go library
gommon/color at master · labstack/gommon
gommon/color at master · labstack/gommon
GitHub - blevesearch/bleve: A modern text/numeric/geo-spatial/vector indexing library for go
GitHub - blevesearch/bleve: A modern text/numeric/geo-spatial/vector indexing library for go
GitHub - schollz/progressbar: A really basic thread-safe progress bar for Golang applications
GitHub - schollz/progressbar: A really basic thread-safe progress bar for Golang applications
GitHub - free/concurrent-writer: Highly concurrent drop-in replacement for bufio.Writer
GitHub - free/concurrent-writer: Highly concurrent drop-in replacement for bufio.Writer
GitHub - mattn/go-colorable
GitHub - mattn/go-colorable
GitHub - StudioSol/set: A simple Set data structure implementation in Go (Golang) using LinkedHashMap.
GitHub - StudioSol/set: A simple Set data structure implementation in Go (Golang) using LinkedHashMap.
GitHub - essentialkaos/branca: Authenticated encrypted API tokens (IETF XChaCha20-Poly1305 AEAD) for Golang
GitHub - essentialkaos/branca: Authenticated encrypted API tokens (IETF XChaCha20-Poly1305 AEAD) for Golang
Cloud Native Computing Foundation
Cloud Native Computing Foundation
GitHub - sakirsensoy/genv: Genv is a library for Go (golang) that makes it easy to read and use environment variables in your projects. It also allows environment variables to be loaded from the .env file.
GitHub - sakirsensoy/genv: Genv is a library for Go (golang) that makes it easy to read and use environment variables in your projects. It also allows environment variables to be loaded from the .env file.
GitHub - heetch/confita: Load configuration in cascade from multiple backends into a struct
GitHub - heetch/confita: Load configuration in cascade from multiple backends into a struct
GitHub - brianvoe/sjwt: Simple JWT Golang
GitHub - brianvoe/sjwt: Simple JWT Golang
GitHub - subpop/go-ini: Go package that encodes and decodes INI-files
GitHub - subpop/go-ini: Go package that encodes and decodes INI-files
GitHub - DylanMeeus/GoAudio: Go tools for audio processing & creation 🎶
GitHub - DylanMeeus/GoAudio: Go tools for audio processing & creation 🎶
GitHub - daviddengcn/go-colortext: Change the color of console text.
GitHub - daviddengcn/go-colortext: Change the color of console text.
GitHub - andOTP/andOTP: [Unmaintained] Open source two-factor authentication for Android
GitHub - andOTP/andOTP: [Unmaintained] Open source two-factor authentication for Android
GitHub - alfiankan/crab-config-files-templating: Dynamic configuration file templating tool for kubernetes manifest or general configuration files
GitHub - alfiankan/crab-config-files-templating: Dynamic configuration file templating tool for kubernetes manifest or general configuration files
GitHub - viney-shih/go-cache: A flexible multi-layer Go caching library to deal with in-memory and shared cache by adopting Cache-Aside pattern.
GitHub - viney-shih/go-cache: A flexible multi-layer Go caching library to deal with in-memory and shared cache by adopting Cache-Aside pattern.
GitHub - TreyBastian/colourize: An ANSI colour terminal package for Go
GitHub - TreyBastian/colourize: An ANSI colour terminal package for Go
GitHub - Evertras/bubble-table: A customizable, interactive table component for the Bubble Tea framework
GitHub - Evertras/bubble-table: A customizable, interactive table component for the Bubble Tea framework
GitHub - deatil/go-array: A Go package that read or set data from map, slice or json
GitHub - deatil/go-array: A Go package that read or set data from map, slice or json
GitHub - cometbft/cometbft: CometBFT (fork of Tendermint Core): A distributed, Byzantine fault-tolerant, deterministic state machine replication engine
GitHub - cometbft/cometbft: CometBFT (fork of Tendermint Core): A distributed, Byzantine fault-tolerant, deterministic state machine replication engine
GitHub - icza/session: Go session management for web servers (including support for Google App Engine - GAE).
GitHub - icza/session: Go session management for web servers (including support for Google App Engine - GAE).
GitHub - cristalhq/jwt: Safe, simple and fast JSON Web Tokens for Go
GitHub - cristalhq/jwt: Safe, simple and fast JSON Web Tokens for Go
GitHub - lrita/cmap: a thread-safe concurrent map for go
GitHub - lrita/cmap: a thread-safe concurrent map for go
GitHub - wzshiming/ctc: Console Text Colors - The non-invasive cross-platform terminal color library does not need to modify the Print method
GitHub - wzshiming/ctc: Console Text Colors - The non-invasive cross-platform terminal color library does not need to modify the Print method
GitHub - goradd/maps: map library using Go generics that offers a standard interface, go routine synchronization, and sorting
GitHub - goradd/maps: map library using Go generics that offers a standard interface, go routine synchronization, and sorting
GitHub - alfiankan/teleterm: Telegram Bot Exec Terminal Command
GitHub - alfiankan/teleterm: Telegram Bot Exec Terminal Command
GitHub - JeremyLoy/config: 12 factor configuration as a typesafe struct in as little as two function calls
GitHub - JeremyLoy/config: 12 factor configuration as a typesafe struct in as little as two function calls
GitHub - goraz/onion: Layer based configuration for golang
GitHub - goraz/onion: Layer based configuration for golang
Golang
More on Golang

Programming Tips & Tricks

Code smarter, not harder—insider tips and tricks for developers.

Error Solutions

Turn frustration into progress—fix errors faster than ever.

Shortcuts

The art of speed—shortcuts to supercharge your workflow.
  1. Collections 😎
  2. Frequently Asked Question's 🤯

Tools

available to use.

Made with ❤️

to provide resources in various ares.