Golang Minimalist Dependency Injection Framework 🪡

🔧 Installation
go get github.com/Ignaciojeria/ioc@latest
The framework infers dependencies automatically by matching parameter types to return types. No need to declare dependencies manually.
It also features 100% type-safety, ambiguous dependency detection, and IDE-clickable error traces (file:line).
👨💻 Quick Example
package myapp
import "github.com/Ignaciojeria/ioc"
// Just register constructors — dependencies are inferred by type.
var _ = ioc.Register(NewEvent)
var _ = ioc.Register(NewGreeter)
var _ = ioc.Register(NewMessage)
type Message string
func NewMessage() Message {
return Message("Hi there!")
}
type Greeter struct {
Message Message
}
func NewGreeter(m Message) Greeter {
return Greeter{Message: m}
}
type Event struct {
Greeter Greeter
}
func NewEvent(g Greeter) Event {
return Event{Greeter: g}
}
Then in your main:
func main() {
if err := ioc.LoadDependencies(); err != nil {
log.Fatal(err)
}
fmt.Println("Dependencies loaded!")
}
🛑 Graceful Shutdown
The framework natively supports graceful shutdowns through dependency injection. Just request the ioc.Shutdowner interface in your constructors:
func NewPostgresDB(s ioc.Shutdowner) (*DB, error) {
db, err := sql.Open("postgres", "...")
if err != nil {
return nil, err
}
// The framework auto-injects itself and registers your cleanup function
s.RegisterShutdown(func() error {
return db.Close()
})
return db, nil
}
Then in your entry point, call ioc.Shutdown() after receiving a termination signal. Cleanups are executed in reverse order (LIFO).
import (
"log"
"os"
"os/signal"
"syscall"
"github.com/Ignaciojeria/ioc"
)
func main() {
if err := ioc.LoadDependencies(); err != nil {
log.Fatal(err)
}
// Wait for termination signal (e.g. Ctrl+C or Kubernetes SIGTERM)
quit := make(chan os.Signal, 1)
signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
<-quit
// Execute graceful shutdown
if err := ioc.Shutdown(); err != nil {
log.Fatalf("Shutdown errors: %v", err)
}
}
🧠 How it works
graph TD
A["1. Register constructors (any order)"] --> B["2. LoadDependencies()"]
B --> C["Match parameter types to return types"]
C --> D["Build DAG edges automatically"]
D --> E["Topological sort"]
E --> F["Invoke constructors (leaves first)"]
F --> G["Invoke RegisterAtEnd constructors"]
Example dependency graph:
graph BT
NewMessage["NewMessage() → Message"] --> NewGreeter["NewGreeter(Message) → Greeter"]
NewGreeter --> NewEvent["NewEvent(Greeter) → Event"]
NewEvent -.-> AtEnd["RegisterAtEnd: StartServer(Event)"]
📌 API
| Function |
Description |
ioc.Register(ctor) |
Register a constructor (dependencies inferred by type) |
ioc.RegisterAtEnd(ctor) |
Register a constructor to run after all others |
ioc.LoadDependencies() |
Resolve the dependency graph and invoke all constructors |
ioc.Shutdown() |
Execute all registered shutdown functions in reverse order (LIFO) |
📜 License
MIT