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
- manager-vs-service — what Manager and Service are; interfaces make them testable
- package-level-vs-constructor — constructor pattern that returns this interface