Structure

Public interface + private implementation + constructor returning the interface.

type BaseMgr interface {
    GetJwtFromEntityCode(ctx context.Context, entityCode string) (string, error)
    GetSets(ctx context.Context, req *v0_3.GetSetsReq_V0_3_0, jwt string) (*v0_3.GetSetsResp_V0_3_0, error)
}
 
type baseMgr struct { ... }
 
func NewBaseMgr(db *gorm.DB) BaseMgr {
    return &baseMgr{ ... }
}
 
// Compile-time check — fails to build if *baseMgr doesn't implement BaseMgr
var _ BaseMgr = (*baseMgr)(nil)

Dependency injection

  • External (varies per environment, needed for tests) → inject via constructor parameter
  • Internal (fixed config) → create inside the constructor
func NewBaseMgr(db *gorm.DB) BaseMgr {
    return &baseMgr{
        httpClient: &http.Client{Timeout: 30 * time.Second}, // internal
        db:         db,                                       // injected
    }
}

Wiring in main

rpcV0_3.RegisterSetsServiceServer(
    grpc,
    setsService.NewService(dbObj, bb3iam.NewBaseMgr(dbObj)),
)

Callers store and use the interface, never the concrete type — swappable for mocks in tests.

See also