2

I have a struct StructDependingOnInterface which depends on MyInterface interface. I'd like the struct Implementation to be injected into bar when StructDependingOnInterface is instantiated.

I have tried doing this with facebookgo/inject library, but it seems like it doesn't work with interfaces. s.bar is always nil.

package main

import (
    "fmt"
    "log"

    "github.com/facebookgo/inject"
)

type MyInterface interface {
    Foo()
}

type Implementation struct{}

func (imp *Implementation) Foo() {
    fmt.Println("Hello")
}

type StructDependingOnInterface struct {
    bar MyInterface `inject:""`
}

func main() {
    var g inject.Graph

    err := g.Provide(
        &inject.Object{Value: &Implementation{}},
    )
    if err != nil {
        log.Fatal(err)
    }

    g.Populate()

    s := &StructDependingOnInterface{}
    s.bar.Foo()
}

Does the language go allows what I'm trying to do ?

Is there an alternative of facebookgo/inject that would fits my need ?

6
  • Create a receiver of StructDependingOnInterface type on Foo implementing interface Commented Mar 24, 2018 at 9:08
  • I don't really know what you mean. Commented Mar 24, 2018 at 9:32
  • Its like you are using implementation struct for Foo(). Also you cannot call Foo on nil Pointer as in you did for s.bar.Foo() where is s.bar is nil cannot be deference to call Foo(). As the error shows Commented Mar 24, 2018 at 9:39
  • @Greg You need to export bar I believe, i.e. changing it to Bar... see here: github.com/facebookgo/inject/blob/… Commented Mar 24, 2018 at 9:48
  • Does this answer your question? Is there a better dependency injection pattern in golang? Commented Sep 3, 2021 at 11:11

2 Answers 2

3

facebookgo/inject should be able to handle interfaces, look at the example in the link and how they use http.RoundTripper and http.DefaultTransport.

First you need to export bar, i.e. changing it to Bar. Then you also need to pass s to Provide for g.Populate to then be able to set Bar.

type StructDependingOnInterface struct {
    Bar MyInterface `inject:""`
}

func main() {
    var g inject.Graph

    s := &StructDependingOnInterface{}
    err := g.Provide(
        &inject.Object{Value: s},
        &inject.Object{Value: &Implementation{}},
    )
    if err != nil {
        log.Fatal(err)
    }

    if err := g.Populate(); err != nil {
         log.Fatal(err)
    }

    s.bar.Foo()
}
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks it works ! Can we make it work if Implementation also has a injectable dependency ?
I believe so, as long as you export the field and pass an instance of the dependency to Provide.
@Greg also note that if the dependency is a concrete type, as opposed to an interface type, you don't have to pass an instance of it to Provide since the library knows what type to instantiate, which is not the case if it's an interface. If you look at the example in their documentation, they don't pass NameAPI and PlanetAPI to Provide as they can infer the types from the fields of HomePlanetRenderApp.
Why is it that inconvenient ? In a clean architecture with 3 layers, controllers, business logic and data access, I have to instantiate the struct of the 2 first layers. I come from a .NET world where I just need to do AddTransient<Interface, Implementation>() and an instance of Implementation will be injected everywhere I use Interface in a constructor. Doesn't Golang allow something like that ?
@Greg I don't know .NET or any other language/environment/framework that might have a DI comparable to what you have in mind and so I cannot say whether it would, or would not, be possible to implement such a DI in Go so as to alleviate the perceived inconvenience. But, if you're interested, take a look at go generate, with that you should be able generate the code that's causing you the inconvenience.
0

hiboot is an cli/web framework that support dependency injection written in Go.

Code: https://github.com/hidevopsio/hiboot

Hiboot Overview
  • Web MVC (Model-View-Controller).
  • Auto Configuration, pre-create instance with properties configs for dependency injection.
  • Dependency injection with struct tag name inject:"" or Constructor func.
Sample Code:
package main

import (
    "github.com/hidevopsio/hiboot/pkg/app/web"
    "github.com/hidevopsio/hiboot/pkg/model"
    "github.com/hidevopsio/hiboot/pkg/starter/jwt"
    "time"
)

// This example shows that token is injected through constructor,
// once you imported "github.com/hidevopsio/hiboot/pkg/starter/jwt",
// token jwt.Token will be injectable.
func main() {
    // create new web application and run it
    web.NewApplication().Run()
}

// PATH: /login
type loginController struct {
    web.Controller

    token jwt.Token
}

type userRequest struct {
    // embedded field model.RequestBody mark that userRequest is request body
    model.RequestBody
    Username string `json:"username" validate:"required"`
    Password string `json:"password" validate:"required"`
}

func init() {
    // Register Rest Controller through constructor newLoginController
    web.RestController(newLoginController)
}

// inject token through the argument token jwt.Token on constructor newLoginController, you may wonder why is token come from
// well, it provided by hiboot starter jwt, see above hiboot link for more details
func newLoginController(token jwt.Token) *loginController {
    return &loginController{
        token: token,
    }
}

// Post /
// The first word of method is the http method POST, the rest is the context mapping
func (c *loginController) Post(request *userRequest) (response model.Response, err error) {
    jwtToken, _ := c.token.Generate(jwt.Map{
        "username": request.Username,
        "password": request.Password,
    }, 30, time.Minute)

    response = new(model.BaseResponse)
    response.SetData(jwtToken)

    return
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.