{"id":31377512,"url":"https://github.com/junioryono/godi","last_synced_at":"2026-01-22T06:24:08.854Z","repository":{"id":304116429,"uuid":"1017068108","full_name":"junioryono/godi","owner":"junioryono","description":"Dependency Injection with Service Lifetimes for Go","archived":false,"fork":false,"pushed_at":"2025-12-14T16:36:22.000Z","size":1019,"stargazers_count":62,"open_issues_count":5,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-12-16T10:30:29.849Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://godi.readthedocs.io/en/latest/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/junioryono.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-07-10T01:30:28.000Z","updated_at":"2025-12-14T16:36:26.000Z","dependencies_parsed_at":"2025-07-11T10:14:22.565Z","dependency_job_id":"781a60c3-2dec-4dcf-b0b5-286326f712e1","html_url":"https://github.com/junioryono/godi","commit_stats":null,"previous_names":["junioryono/godi"],"tags_count":41,"template":false,"template_full_name":null,"purl":"pkg:github/junioryono/godi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/junioryono%2Fgodi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/junioryono%2Fgodi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/junioryono%2Fgodi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/junioryono%2Fgodi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/junioryono","download_url":"https://codeload.github.com/junioryono/godi/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/junioryono%2Fgodi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28656773,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-22T01:17:37.254Z","status":"online","status_checked_at":"2026-01-22T02:00:07.137Z","response_time":144,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-09-28T05:00:48.351Z","updated_at":"2026-01-22T06:24:08.844Z","avatar_url":"https://github.com/junioryono.png","language":"Go","funding_links":[],"categories":["Miscellaneous","Microsoft Office","杂项"],"sub_categories":["Dependency Injection","依赖注入"],"readme":"# godi\r\n\r\n[![Go Reference](https://pkg.go.dev/badge/github.com/junioryono/godi/v4.svg)](https://pkg.go.dev/github.com/junioryono/godi/v4)\r\n[![Go Report Card](https://goreportcard.com/badge/github.com/junioryono/godi)](https://goreportcard.com/report/github.com/junioryono/godi)\r\n[![Build Status](https://github.com/junioryono/godi/actions/workflows/test.yml/badge.svg)](https://github.com/junioryono/godi/actions/workflows/test.yml)\r\n[![Coverage](https://codecov.io/gh/junioryono/godi/branch/main/graph/badge.svg)](https://codecov.io/gh/junioryono/godi)\r\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\r\n\r\n**Dependency injection for Go with service lifetimes.** godi automatically wires your application, manages service lifetimes, and handles cleanup - so you can focus on business logic.\r\n\r\n```go\r\nservices := godi.NewCollection()\r\nservices.AddSingleton(NewDatabase)     // One instance, shared everywhere\r\nservices.AddScoped(NewUserService)     // One instance per request\r\nservices.AddTransient(NewEmailBuilder) // New instance every time\r\n\r\nprovider, _ := services.Build()\r\nuser := godi.MustResolve[*UserService](provider)\r\n```\r\n\r\n## Why godi?\r\n\r\n**The problem:** As applications grow, manually wiring dependencies becomes painful. Constructor parameters multiply, initialization order matters, and per-request isolation requires careful scope management.\r\n\r\n```go\r\n// Manual wiring - gets messy fast\r\nconfig := NewConfig()\r\nlogger := NewLogger(config)\r\ndb := NewDatabase(config, logger)\r\ncache := NewCache(config, logger)\r\nuserRepo := NewUserRepository(db, cache, logger)\r\norderRepo := NewOrderRepository(db, cache, logger)\r\nuserService := NewUserService(userRepo, logger)\r\norderService := NewOrderService(orderRepo, userService, logger)\r\n// ... 20 more lines\r\n```\r\n\r\n**The solution:** Register constructors. godi figures out the rest.\r\n\r\n```go\r\n// godi - register in any order, resolve anything\r\nservices := godi.NewCollection()\r\nservices.AddSingleton(NewConfig)\r\nservices.AddSingleton(NewLogger)\r\nservices.AddSingleton(NewDatabase)\r\nservices.AddScoped(NewUserService)\r\n// ... godi handles the wiring\r\n```\r\n\r\n## Installation\r\n\r\n```bash\r\ngo get github.com/junioryono/godi/v4\r\n```\r\n\r\nRequires **Go 1.21+**. Zero external dependencies.\r\n\r\n## Quick Start\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n    \"fmt\"\r\n    \"github.com/junioryono/godi/v4\"\r\n)\r\n\r\ntype Logger struct{}\r\nfunc (l *Logger) Log(msg string) { fmt.Println(msg) }\r\nfunc NewLogger() *Logger { return \u0026Logger{} }\r\n\r\ntype UserService struct {\r\n    logger *Logger\r\n}\r\nfunc NewUserService(logger *Logger) *UserService {\r\n    return \u0026UserService{logger: logger}\r\n}\r\nfunc (s *UserService) Greet() { s.logger.Log(\"Hello from UserService!\") }\r\n\r\nfunc main() {\r\n    // 1. Register services\r\n    services := godi.NewCollection()\r\n    services.AddSingleton(NewLogger)\r\n    services.AddSingleton(NewUserService)\r\n\r\n    // 2. Build the container\r\n    provider, _ := services.Build()\r\n    defer provider.Close()\r\n\r\n    // 3. Resolve and use - dependencies wired automatically\r\n    users := godi.MustResolve[*UserService](provider)\r\n    users.Greet() // Hello from UserService!\r\n}\r\n```\r\n\r\n## Service Lifetimes\r\n\r\ngodi provides three lifetimes to control when instances are created:\r\n\r\n```\r\n┌──────────────────────────────────────────────────────────────────┐\r\n│  Application                                                     │\r\n│  ┌────────────────────────────────────────────────────────────┐  │\r\n│  │ SINGLETON: Database, Logger, Config                        │  │\r\n│  │ Created once, shared everywhere                            │  │\r\n│  └────────────────────────────────────────────────────────────┘  │\r\n│                                                                  │\r\n│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐            │\r\n│  │  Request 1   │  │  Request 2   │  │  Request 3   │            │\r\n│  │   SCOPED:    │  │   SCOPED:    │  │   SCOPED:    │            │\r\n│  │  Transaction │  │  Transaction │  │  Transaction │            │\r\n│  │  UserSession │  │  UserSession │  │  UserSession │            │\r\n│  └──────────────┘  └──────────────┘  └──────────────┘            │\r\n└──────────────────────────────────────────────────────────────────┘\r\n```\r\n\r\n| Lifetime    | Created        | Shared       | Use Case                      |\r\n| ----------- | -------------- | ------------ | ----------------------------- |\r\n| `Singleton` | Once           | App-wide     | Database pools, config        |\r\n| `Scoped`    | Once per scope | Within scope | Request context, transactions |\r\n| `Transient` | Every time     | Never        | Builders, temp objects        |\r\n\r\n```go\r\nservices.AddSingleton(NewDatabasePool)  // One pool for the whole app\r\nservices.AddScoped(NewTransaction)      // Fresh transaction per request\r\nservices.AddTransient(NewQueryBuilder)  // New builder every resolution\r\n```\r\n\r\n## HTTP Integration\r\n\r\ngodi shines in web applications where each request needs isolated services:\r\n\r\n```go\r\npackage main\r\n\r\nimport (\r\n    \"net/http\"\r\n    \"github.com/junioryono/godi/v4\"\r\n    godihttp \"github.com/junioryono/godi/v4/http\"\r\n)\r\n\r\ntype UserController struct {\r\n    // Dependencies injected automatically\r\n}\r\n\r\nfunc (c *UserController) List(w http.ResponseWriter, r *http.Request) {\r\n    w.Write([]byte(`[\"alice\", \"bob\"]`))\r\n}\r\n\r\nfunc main() {\r\n    services := godi.NewCollection()\r\n    services.AddSingleton(NewLogger)\r\n    services.AddScoped(NewUserController)\r\n\r\n    provider, _ := services.Build()\r\n    defer provider.Close()\r\n\r\n    mux := http.NewServeMux()\r\n    mux.HandleFunc(\"GET /users\", godihttp.Handle((*UserController).List))\r\n\r\n    // ScopeMiddleware creates a fresh scope per request\r\n    handler := godihttp.ScopeMiddleware(provider)(mux)\r\n    http.ListenAndServe(\":8080\", handler)\r\n}\r\n```\r\n\r\n### Framework Support\r\n\r\n| Framework | Package                               | Install                                      |\r\n| --------- | ------------------------------------- | -------------------------------------------- |\r\n| net/http  | `github.com/junioryono/godi/v4/http`  | `go get github.com/junioryono/godi/v4/http`  |\r\n| Gin       | `github.com/junioryono/godi/v4/gin`   | `go get github.com/junioryono/godi/v4/gin`   |\r\n| Chi       | `github.com/junioryono/godi/v4/chi`   | `go get github.com/junioryono/godi/v4/chi`   |\r\n| Echo      | `github.com/junioryono/godi/v4/echo`  | `go get github.com/junioryono/godi/v4/echo`  |\r\n| Fiber     | `github.com/junioryono/godi/v4/fiber` | `go get github.com/junioryono/godi/v4/fiber` |\r\n\r\n## Features\r\n\r\n### Interface Binding\r\n\r\nRegister concrete types as interfaces for easy testing and swapping:\r\n\r\n```go\r\nservices.AddSingleton(NewConsoleLogger, godi.As[Logger]())\r\n\r\n// Resolve by interface\r\nlogger := godi.MustResolve[Logger](provider)\r\n```\r\n\r\n### Keyed Services\r\n\r\nMultiple implementations of the same type:\r\n\r\n```go\r\nservices.AddSingleton(NewPrimaryDB, godi.Name(\"primary\"))\r\nservices.AddSingleton(NewReplicaDB, godi.Name(\"replica\"))\r\n\r\nprimary := godi.MustResolveKeyed[Database](provider, \"primary\")\r\nreplica := godi.MustResolveKeyed[Database](provider, \"replica\")\r\n```\r\n\r\n### Service Groups\r\n\r\nCollect related services for batch operations:\r\n\r\n```go\r\nservices.AddSingleton(NewEmailValidator, godi.Group(\"validators\"))\r\nservices.AddSingleton(NewPhoneValidator, godi.Group(\"validators\"))\r\n\r\nvalidators := godi.MustResolveGroup[Validator](provider, \"validators\")\r\nfor _, v := range validators {\r\n    v.Validate(input)\r\n}\r\n```\r\n\r\n### Parameter Objects\r\n\r\nSimplify constructors with many dependencies:\r\n\r\n```go\r\ntype ServiceParams struct {\r\n    godi.In\r\n    DB      Database\r\n    Cache   Cache\r\n    Logger  Logger\r\n    Metrics Metrics `optional:\"true\"`\r\n}\r\n\r\nfunc NewService(params ServiceParams) *Service {\r\n    return \u0026Service{db: params.DB, cache: params.Cache}\r\n}\r\n```\r\n\r\n### Result Objects\r\n\r\nRegister multiple services from one constructor:\r\n\r\n```go\r\ntype InfraResult struct {\r\n    godi.Out\r\n    DB     *Database\r\n    Cache  *Cache\r\n    Health *HealthChecker\r\n}\r\n\r\nfunc NewInfra(cfg *Config) InfraResult {\r\n    db := connectDB(cfg)\r\n    return InfraResult{\r\n        DB:     db,\r\n        Cache:  NewCache(cfg),\r\n        Health: NewHealthChecker(db),\r\n    }\r\n}\r\n\r\n// One registration, three services\r\nservices.AddSingleton(NewInfra)\r\n```\r\n\r\n### Modules\r\n\r\nOrganize large applications:\r\n\r\n```go\r\n// users/module.go\r\nvar Module = godi.NewModule(\"users\",\r\n    godi.AddScoped(NewUserRepository),\r\n    godi.AddScoped(NewUserService),\r\n)\r\n\r\n// main.go\r\nservices.AddModules(\r\n    infrastructure.Module,\r\n    users.Module,\r\n    orders.Module,\r\n)\r\n```\r\n\r\n### Automatic Cleanup\r\n\r\nServices implementing `Close() error` are cleaned up automatically:\r\n\r\n```go\r\nfunc (d *Database) Close() error {\r\n    return d.conn.Close()\r\n}\r\n\r\nprovider.Close() // Database.Close() called automatically\r\n```\r\n\r\n## Error Handling\r\n\r\ngodi validates at build time to catch problems early:\r\n\r\n```go\r\nprovider, err := services.Build()\r\nif err != nil {\r\n    // Circular dependency? Missing service? Lifetime conflict?\r\n    // The error message tells you exactly what's wrong\r\n    log.Fatal(err)\r\n}\r\n```\r\n\r\nCommon errors caught at build time:\r\n\r\n- **Circular dependencies** - `*A -\u003e *B -\u003e *A`\r\n- **Missing dependencies** - `*UserService requires *Database (not registered)`\r\n- **Lifetime conflicts** - `singleton *Cache cannot depend on scoped *RequestContext`\r\n\r\n## Testing\r\n\r\nReplace implementations for testing:\r\n\r\n```go\r\nfunc TestUserService(t *testing.T) {\r\n    services := godi.NewCollection()\r\n    services.AddSingleton(func() Database { return \u0026MockDB{} })\r\n    services.AddScoped(NewUserService)\r\n\r\n    provider, _ := services.Build()\r\n    defer provider.Close()\r\n\r\n    scope, _ := provider.CreateScope(context.Background())\r\n    defer scope.Close()\r\n\r\n    svc := godi.MustResolve[*UserService](scope)\r\n    // Test with mock database\r\n}\r\n```\r\n\r\n## Comparison\r\n\r\n| Feature                    | godi | Wire | Fx  | do  |\r\n| -------------------------- | ---- | ---- | --- | --- |\r\n| No code generation         | Yes  | No   | Yes | Yes |\r\n| Service lifetimes          | Yes  | No   | No  | No  |\r\n| Scoped services            | Yes  | No   | No  | No  |\r\n| Build-time validation      | Yes  | Yes  | No  | No  |\r\n| HTTP framework integration | Yes  | No   | No  | No  |\r\n| Parameter objects          | Yes  | No   | Yes | No  |\r\n| Automatic cleanup          | Yes  | No   | Yes | Yes |\r\n\r\n## Performance\r\n\r\nBenchmarks comparing godi with [dig](https://github.com/uber-go/dig) (Uber's DI, powers Fx) and [do](https://github.com/samber/do) (samber's DI).\r\n\r\nRun on Apple M2 Max. [Source code](benchmarks/comparison_test.go).\r\n\r\n### Singleton Resolution\r\n\r\n| Library | ns/op | B/op | allocs/op | vs godi |\r\n| ------- | ----: | ---: | --------: | ------: |\r\n| godi    |    55 |    0 |         0 |      1x |\r\n| do      |   180 |  192 |         6 |    3.3x |\r\n| dig     |   640 |  736 |        20 |     12x |\r\n\r\ngodi uses a lock-free cache with **zero allocations**. Singletons are created at build time, so every resolution is a fast cache lookup.\r\n\r\n### Concurrent Resolution\r\n\r\n| Library | ns/op | B/op | allocs/op | vs godi |\r\n| ------- | ----: | ---: | --------: | ------: |\r\n| godi    |     7 |    0 |         0 |      1x |\r\n| do      |   297 |  224 |         6 |     42x |\r\n| dig     |   366 |  736 |        20 |     52x |\r\n\r\nUnder high concurrency, godi is **40-50x faster** with zero contention.\r\n\r\n### Transient Resolution\r\n\r\n| Library | ns/op | B/op | allocs/op |\r\n| ------- | ----: | ---: | --------: |\r\n| godi    |   176 |   40 |         2 |\r\n| do      |   188 |  208 |         7 |\r\n\r\nNew instance created on each call.\r\n\r\n### Cold Start\r\n\r\n| Library |  ns/op |   B/op | allocs/op | vs godi |\r\n| ------- | -----: | -----: | --------: | ------: |\r\n| godi    | 17,500 | 21,064 |       155 |      1x |\r\n| dig     | 36,000 | 37,665 |       549 |    2.1x |\r\n| do      | 47,000 | 30,511 |       351 |    2.7x |\r\n\r\nFull cycle: create container, register services, build, resolve. godi is **2x faster** than dig.\r\n\r\n\u003cdetails\u003e\r\n\u003csummary\u003eRun benchmarks yourself\u003c/summary\u003e\r\n\r\n```bash\r\ncd benchmarks \u0026\u0026 go test -bench=. -benchmem\r\n```\r\n\r\n\u003c/details\u003e\r\n\r\n## Documentation\r\n\r\n**[Full Documentation](https://godi.readthedocs.io)**\r\n\r\n- [Getting Started](https://godi.readthedocs.io/en/latest/getting-started/) - 5-minute tutorial\r\n- [Core Concepts](https://godi.readthedocs.io/en/latest/concepts/) - Lifetimes, scopes, modules\r\n- [Features](https://godi.readthedocs.io/en/latest/features/) - Keyed services, groups, parameter objects\r\n- [Integrations](https://godi.readthedocs.io/en/latest/integrations/) - Gin, Chi, Echo, Fiber, net/http\r\n- [Guides](https://godi.readthedocs.io/en/latest/guides/) - Web apps, testing, error handling\r\n- [API Reference](https://pkg.go.dev/github.com/junioryono/godi/v4)\r\n\r\n## Contributing\r\n\r\nContributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\r\n\r\n## License\r\n\r\nMIT License - see [LICENSE](LICENSE) for details.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjunioryono%2Fgodi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjunioryono%2Fgodi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjunioryono%2Fgodi/lists"}