digpro is a enhanced uber-go/dig

Overview

⚒️ digpro

MIT GoDoc GitHub release Build Status Coverage Status Go Report Card

English | 简体中文

Introduction

digpro is a enhanced uber-go/dig, inherit all feature of uber-go/dig and add the following features:

  • Progressive use digpro
  • Value Provider
  • Property dependency injection
  • Extract object from the container
  • Override a registered Provider
  • Add global container
  • Export some function
    • QuickPanic function
    • Visualize function
    • Unwrap function

Installation

go get github.com/rectcircle/digpro

Document

https://pkg.go.dev/github.com/rectcircle/digpro

Guide

dig Introduction

uber-go/dig is a lightweight dependency injection library that supported by uber for go language. The library driven by reflection and has the following features:

  • Dependency injection based on constructor
  • Object and interface binding
  • Named objects and group objects
  • Parameter object, result object and optional dependencies

More see: go docs

Why need digpro

dig provides a very lightweight runtime dependency injection, and the code is high-quality and stable. But it lacks the following more useful features:

  • Property dependency injection, by simply providing a structure type, the dependency injection library can construct a structure object and inject the dependency into that object and into the container. This feature can save dependency injection users a lot of time and avoid writing a lot of sample constructors.
  • Value Provider, which can take a constructed object provided by the user and put it directly into a container.
  • Extract Object, which extracts the constructed object from the container for use.

Progressive use

Lower level API

Containers constructed with c := dig.New() can be used directly. use it like

c := dig.New()
c.Provide(digpro.Supply(...))
c.Provide(digpro.Struct(...))
digpro.Extract(c, ...)

This approach introduces all the capabilities provided by digpro at zero cost to projects already using dig. However, due to a limitation of the principle, this method reports errors without the correct code file and line number information, and only displays the following information

... missing dependencies for function "reflect".makeFuncStub (/usr/local/Cellar/go/1.17.1/libexec/src/reflect/asm_amd64.s:30) ...

Therefore, if starting from scratch with digpro it is recommended to use the High level API or the global container.

High level API

Construct a wrapper object for dig.Container (digpro.ContainerWrapper) with c := digpro.New(). use it like

c := digpro.New()
c.Supply(...)
c.Struct(...)
c.Extract(...)

This approach is much more elegant and simple than the low-level API.

Global container

By importing the digglobal package, you can use the global digpro.ContainerWrapper object, which can be used if you are looking for the ultimate efficiency

import "github.com/rectcircle/digpro/digglobal"

// dao/module.go
func init() {
  digglobal.Struct(new(XxxDAO))
  digglobal.Struct(new(XxxDAO))
  digglobal.Struct(new(XxxDAO))
}

// service/module.go
func init() {
  digglobal.Struct(new(XxxService))
  digglobal.Struct(new(XxxService))
  digglobal.Struct(new(XxxService))
}

// controller/module.go
func init() {
  digglobal.Struct(new(XxxService))
  digglobal.Struct(new(XxxService))
  digglobal.Struct(new(XxxService))
}

// main.go
func main() {
  digglobal.Supply(Config{})
  digglobal.Supply(DB{})
  digglobal.Provide(NewServer)
  server, err := digglobal.Extract(new(Server))
  digpro.QuickPanic(err)
  server.Run()
}

Note: For global containers, functions of type Provider (Provide, Struct, Supply) will no longer return an error, directly Panic

Value Provider

It can take a constructed object provided by the user and put it directly into a container.

func Supply(value interface{}) interface{}
func (c *ContainerWrapper) Supply(value interface{}, opts ...dig.ProvideOption) error
  • The value parameter supports any non-error type
  • If value is untyped nil, then the object in the container with type = interface{} and value = nil

Example

// High Level API
c.Supply("a")
// Lower Level API
c.Provide(digpro.Supply("a"))

Equals to

c.Provide(func() string {return "a"})

Property dependency injection

By simply providing a structure type, the dependency injection library can construct a structure object and inject the dependency into that object and into the container.

func Struct(structOrStructPtr interface{}) interface{}
func (c *ContainerWrapper) Struct(structOrStructPtr interface{}, opts ...dig.ProvideOption) error
  • structOrStructPtr must be of struct type, or struct pointer type

Example

type Foo struct {
	A       string
	B       int
	C       int `name:"c"`
	private bool
	ignore  int `digpro:"ignore"`
}
// High Level API
c.Struct(Foo{
  ignore: 3,
})
// Lower Level API
c.Provide(digpro.Struct(Foo{
  ignore: 3,
}))

Equals to

c.Provide(func(in struct {
  A       string
  B       int
  C       int `name:"c"`
  Private bool
}) Foo {
  return Foo{
    A:       in.A,
    B:       in.B,
    C:       in.C,
    private: in.Private,
    ignore:  3,
  }
}),

Extract object

Extracts the object constructed inside the container for use.

func MakeExtractFunc(ptr interface{}, opts ...ExtractOption) interface{}
func Extract(c *dig.Container, typ interface{}, opts ...ExtractOption) (interface{}, error)
func (c *ContainerWrapper) Extract(typ interface{}, opts ...ExtractOption) (interface{}, error)

For two Extract functions, if want to extract a non-interface, reflect.TypeOf(result) == reflect.TypeOf(typ)

func(int) -> int    // func(int(0)) -> int
func(*int) -> *int  // func(new(int)) -> *int

For two Extract functions, if want to extract a interface, reflect.TypeOf(result) == reflect.TypeOf(typ).Elem()

type A interface { ... }
func(A) -> error   // func(A(nil)) -> error
func(*A) -> A      // func(new(A)) -> A
func(**A) -> *A    // func(new(*A)) -> *A

Example

// High Level API
i, err := c.Extract(int(0)) 
// Lower Level API (1)
i, err := digpro.Extract(c, int(0))
// Lower Level API (2)
var i int
err := digpro.Invoke(digpro.MakeExtractFunc(&i))

Equals to

var i interface{}
err := c.Invoke(func(_i int){
  i = _i
})

Override

⚠️ Only support High Level API

When using dependency injection, the Provider is registered according to the configuration of the production environment, and the service is started in the main function. When starting a service in another environment (e.g. testing), it is generally only necessary to replace a small number of the production environment's Providers with proprietary ones (e.g. db mock).

To more elegantly support scenarios such as the above, add the Override capability.

Example

c := digpro.New()
_ = c.Supply(1) // please handle error in production
_ = c.Supply(1, digpro.Override())
// _ = c.Supply("a", digpro.Override())  // has error
i, _ := c.Extract(0)
fmt.Println(i.(int) == 1)
// Output: true

To expose the problem in advance, using digpro.Override() will return the error no provider to override was found if the same Provider does not exist in the container

Others

QuickPanic

func QuickPanic(errs ...error)

If any of the errs is not nil, it will panic directly

Example

c := digpro.New()
digpro.QuickPanic(
	c.Supply(1),
	c.Supply(1),
)
// panic: [1]: cannot provide function "xxx".Xxx (xxx.go:n): cannot provide int from [0]: already provided by "xxx".Xxx (xxx.go:m)

Visualize

func (c *ContainerWrapper) Visualize(w io.Writer, opts ...dig.VisualizeOption) error

Write dot graph to io.Writer.

Unwrap

func (c *ContainerWrapper) Unwrap() *dig.Container

From *digpro.ContainerWrapper obtain *dig.Container

TODO

  • Circular reference problem (change high level api StructInvoke and Extract Implementation as () => new(struct), and assembled at the time of extraction)(disregarding the non-pointer case)
Issues
Releases(v1.2.0)
  • v1.2.0(Nov 20, 2021)

  • v1.1.0(Oct 14, 2021)

    1.1.0 - 2021-10-14 https://github.com/rectcircle/digpro/pull/2

    Add

    • digpro.Override() API for override a registered provider
    • digpro.MakeExtractFunc(ptr) API for make Invoke function to extract a value and assign to *ptr from dig.Container

    Fixed

    • dig.RootCause() may be not work
    • Extract() can't extract interface type value
    • README spell

    Security

    • improve test coverage
    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Oct 8, 2021)

    1.0.0 - 2021-10-08

    Add

    • Progressive use digpro
    • Value Provider
    • Property dependency injection
    • Extract object from the container
    • Add global container
    • Export some function
      • QuickPanic function
      • Visualize function
      • Unwrap function
    Source code(tar.gz)
    Source code(zip)
uber's ssh certificate pam module

Uber's SSH certificate pam module. This is a pam module that will authenticate a user based on them having an ssh certificate in their ssh-agent signe

Uber Open Source 712 Nov 29, 2021
A fully-featured AWS Athena database driver (+ athenareader https://github.com/uber/athenadriver/tree/master/athenareader)

?? athenadriver - A fully-featured AWS Athena database driver for Go ?? athenareader - A moneywise command line utililty to query athena in command li

Uber Open Source 91 Nov 24, 2021
基于 Echo + Gorm + Casbin + Uber-FX 实现的 RBAC 权限管理脚手架,致力于提供一套尽可能轻量且优雅的中后台解决方案。

Echo-Admin 基于 Echo + Gorm + Casbin + Uber-FX 实现的 RBAC 权限管理脚手架,致力于提供一套尽可能轻量且优雅的中后台解决方案。 English | 简体中文 特性 遵循 RESTful API 设计规范 基于 Echo API 框架,提供了丰富的中间件支

LiuSha 144 Nov 22, 2021
Golimit is Uber ringpop based distributed and decentralized rate limiter

Golimit A Distributed Rate limiter Golimit is Uber ringpop based distributed and decentralized rate limiter. It is horizontally scalable and is based

Myntra 592 Nov 27, 2021
微服务架构-micro-基于go-zero zrpc etcd 单独集成orm-gorm 日志-uber/zap

micro目录结构 pkg ├── api 业务接口逻辑层 所有的业务逻辑存放目录。 │ ├── model 数据模型 数据管理层,仅用于操作管理数据,如数据库操作 ├── assets

jiwei 6 Nov 15, 2021
A Handy FieldBuilder Template for uber-go/zap

zap-fieldbuilder-template A Handy Generic Logging FieldBuilder Template around uber-go/zap. You can check this tiny blog for further information ?? Wh

Yavuz Selim Yesilyurt 7 Nov 7, 2021
Package zaperations provides a Google Cloud operations suite (formerly Stackdriver) compatible config for the uber-go/zap logger.

Package zaperations provides a Google Cloud Operations (formerly Stackdriver) compatible config for the excellent uber-go/zap logger. Example This exa

Wayne 0 Nov 6, 2021
A prefix-enhanced map in Go

PrefixMap PrefixMap is a prefix-enhanced map that eases the retrieval of values based on key prefixes. Quick Start Creating a PrefixMap // creates the

Alessandro Diaferia 28 Oct 8, 2021
An enhanced http client for Golang

go-http-client An enhanced http client for Golang Documentation on go.dev ?? This package provides you a http client package for your http requests. Y

Furkan Bozdag 30 Oct 26, 2021
An enhanced HTTP client for Go

Heimdall Description Installation Usage Making a simple GET request Creating a hystrix-like circuit breaker Creating a hystrix-like circuit breaker wi

Gojek 2.1k Nov 27, 2021
An Enhanced Go Experience For The Atom Editor

go-plus An Improved Go Experience For The Atom Editor Github: https://github.com/joefitzgerald/go-plus Atom: https://atom.io/packages/go-plus Overview

Joe Fitzgerald 1.5k Nov 29, 2021
Enhanced PostgreSQL logical replication

pgcat - Enhanced postgresql logical replication Why pgcat? Architecture Build from source Install Run Conflict handling Table mapping Replication iden

jinhua luo 350 Nov 18, 2021
An enhanced HTTP client for Go

Heimdall Description Installation Usage Making a simple GET request Creating a hystrix-like circuit breaker Creating a hystrix-like circuit breaker wi

Gojek 2.1k Nov 28, 2021
A SimpleHTTPServer written in Go, enhanced with features and with a nice design

goshs is a replacement for Python's SimpleHTTPServer. It allows uploading and downloading via HTTP/S with either self-signed certificate or user provi

Patrick Hener 86 Nov 14, 2021
Poseidon -- An Enhanced V2Ray(based on v2ray-core)

Poseidon -- An Enhanced V2Ray(based on v2ray-core) Support SSRPanel(VNetPanel), V2board, SSpanel-v3-Uim Features Sync user from your panel to v2ray Lo

null 0 Nov 14, 2021