Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to have dependency injection in Golang

I'm a beginner in Golang and I'm working on a small library which need to get a DB connection at some point in the code for différent sub package / method call. I'm just wondering how I can manage this ?

Example, If I manage to have a webserver, it works with handler, so how can I get this connection inside this function ? It could be used with another process, simple method call or MVC model ?

I don't want to use global because for me it's a bad practice except if it's very exceptional way (or tricky somehow).

I read a lot of write in different website, but still, I'm asking and learning from different opinion and experiences.

Thanks for your time !

like image 285
Vincent Avatar asked Sep 10 '17 14:09

Vincent


People also ask

Does Golang do dependency injection?

Dependency injection is a programming technique that makes a class independent of its dependencies. It achieves that by decoupling the usage of an object from its creation. This helps you to follow SOLID's dependency inversion and single responsibility principles, in order to write a good programme.

What are the three types of dependency injection?

Types of DI There are three main styles of dependency injection, according to Fowler: Constructor Injection (also known as Type 3), Setter Injection (also known as Type 2), and Interface Injection (also known as Type 1).


2 Answers

Create a struct that represent the resource​, let's call Cart. Add get and post methods to this struct. These methods should be http handlers. In main create an instance of the struct with db interface. And in the route call Cart.get. Now in get method you have access to the db interface.

Not a working example, just to get the idea of injecting for testing.

type storage interface {
    PrepareContext(context.Context, string) (*sql.Stmt, error)
}

func main() {
    db, _ := sql.Open("mysql", `queryString`)
    http.HandleFunc("/", Cart{db}.get)
    http.ListenAndServe(":8080", nil)
}

type Cart struct {
    storage
}

func (crt Cart) get(w http.ResponseWriter, r *http.Request) {
    q, _ := crt.PrepareContext(context.Background(), `select *`)
    fmt.Println(q.Exec())
}

/////////Test
type testDB struct{}

func (c testDB) PrepareContext(context.Context, string) (*sql.Stmt, error) {
    return nil, nil
}
func TestGet(t *testing.T) {
    db := testDB{}
    _ = Cart{db}

    //http test here
}
like image 68
ZAky Avatar answered Oct 19 '22 01:10

ZAky


I would suggest Dargo which is an injection engine in the style of Java CDI and/or JSR-330. It uses struct annotations and Injection is performed using reflection or using creator functions. It supports different lifecycles for services including Singleton (created exactly once, lazily), PerLookup (created every time injected or looked up), Immediate (created exactly once, eagerly) and DargoContext (tied to the lifecycle of a context.Context)

like image 28
jwells131313 Avatar answered Oct 19 '22 02:10

jwells131313