{"id":13413451,"url":"https://github.com/go-kod/kod","last_synced_at":"2025-05-16T07:11:10.115Z","repository":{"id":222641472,"uuid":"740044464","full_name":"go-kod/kod","owner":"go-kod","description":"A generics based dependency injection application framework for Go, supporting aspect oriented programming based on interceptors","archived":false,"fork":false,"pushed_at":"2025-05-13T02:37:53.000Z","size":1273,"stargazers_count":185,"open_issues_count":2,"forks_count":6,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-05-13T03:31:14.847Z","etag":null,"topics":["aop","application","code-generation","dependency-injection","dependency-management","di","do","framework","fx","generics","go","golang","interceptor","microservice","opentelemetry","reflection","spring","spring-boot","wire"],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/go-kod/kod","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/go-kod.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-01-07T11:02:21.000Z","updated_at":"2025-05-13T02:37:56.000Z","dependencies_parsed_at":null,"dependency_job_id":"c558f8bb-4e24-471a-9f67-9e05ca56abb7","html_url":"https://github.com/go-kod/kod","commit_stats":null,"previous_names":["go-kod/kod"],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-kod%2Fkod","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-kod%2Fkod/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-kod%2Fkod/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-kod%2Fkod/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/go-kod","download_url":"https://codeload.github.com/go-kod/kod/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254485042,"owners_count":22078767,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["aop","application","code-generation","dependency-injection","dependency-management","di","do","framework","fx","generics","go","golang","interceptor","microservice","opentelemetry","reflection","spring","spring-boot","wire"],"created_at":"2024-07-30T20:01:40.704Z","updated_at":"2025-05-16T07:11:10.096Z","avatar_url":"https://github.com/go-kod.png","language":"Go","funding_links":[],"categories":["杂项","Miscellaneous","Go","Microsoft Office"],"sub_categories":["依赖注入","Dependency Injection"],"readme":"\u003cdiv align=\"center\"\u003e\n\n[![Build and Test](https://github.com/go-kod/kod/actions/workflows/go.yml/badge.svg)](https://github.com/go-kod/kod/actions/workflows/go.yml)\n[![GitHub Release](https://img.shields.io/github/v/release/go-kod/kod)](https://github.com/go-kod/kod/releases)\n[![Go Report Card](https://goreportcard.com/badge/github.com/go-kod/kod)](https://goreportcard.com/report/github.com/go-kod/kod)\n[![Code Cov](https://codecov.io/github/go-kod/kod/graph/badge.svg?token=FKCHAE6M2R)](https://codecov.io/github/go-kod/kod)\n[![Go Reference](https://pkg.go.dev/badge/github.com/go-kod/kod.svg)](https://pkg.go.dev/github.com/go-kod/kod)\n[![GitHub License](https://img.shields.io/github/license/go-kod/kod)](https://github.com/go-kod/kod/blob/main/LICENSE)\n[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go)\n\n[**English**](./README.md) •\n[**简体中文**](./README_CN.md) |\n[**Examples**](./example_test.go) •\n[**Template**](https://github.com/go-kod/kod-mono) •\n[**Extention**](https://github.com/go-kod/kod-ext)\n\n\u003c/div\u003e\n\n# Kod\n\nKod stands for **Killer Of Dependency**, a generics based dependency injection framework for Go.\n\n\u003e Although it seems that most Go enthusiasts dislike dependency injection framework, many companies that widely use Go for their development projects have open-sourced their own dependency injection frameworks. For example, Google has open-sourced Wire, Uber has open-sourced Fx, and Facebook has open-sourced Inject. This is truly a strange phenomenon.\n\n![kod](/assets/kod.excalidraw.png)\n\n## Feature\n\n- **Component Based**: Kod is a component-based framework. Components are the building blocks of a Kod application.\n- **Configurable**: Kod can use TOML/YAML/JSON files to configure how applications are run.\n- **Testing**: Kod includes a Test function that you can use to test your Kod applications.\n- **Logging**: Kod provides a logging API, `kod.L`. Kod also integrates the logs into the environment where your application is deployed.\n- **OpenTelemetry**: Kod relies on OpenTelemetry to collect trace and metrics from your application.\n- **Hooks**: Kod provides a way to run code when a component start or stop.\n- **Interceptors**: Kod has built-in common interceptors, and components can implement the following methods to inject these interceptors into component methods.\n- **Interface Generation**: Kod provides a way to generate interface from structure.\n- **Code Generation**: Kod provides a way to generate kod related codes for your kod application.\n\n## Installation\n\n```bash\ngo install github.com/go-kod/kod/cmd/kod@latest\n```\n\nIf the installation was successful, you should be able to run `kod -h`:\n\n```bash\nA powerful tool for writing kod applications.\n\nUsage:\n  kod [flags]\n  kod [command]\n\nAvailable Commands:\n  callgraph        generate kod callgraph for your kod application.\n  completion       Generate the autocompletion script for the specified shell\n  generate         generate kod related codes for your kod application.\n  help             Help about any command\n  struct2interface generate interface from struct for your kod application.\n\nFlags:\n  -h, --help      help for kod\n  -t, --toggle    Help message for toggle\n  -v, --version   Help message for toggle\n\nUse \"kod [command] --help\" for more information about a command.\n```\n\n## Step by Step Tutorial\n\nIn this section, we show you how to write Kod applications. To install Kod and follow along, refer to the Installation section. The full source code presented in this tutorial can be found here.\n\n### Components\n\nKod's core abstraction is the component. A component is like an actor, and a Kod application is implemented as a set of components. Concretely, a component is represented with a regular Go interface, and components interact with each other by calling the methods defined by these interfaces.\n\nIn this section, we'll define a simple hello component that just prints a string and returns. First, run `go mod init hello` to create a go module.\n\n```bash\nmkdir hello/\ncd hello/\ngo mod init hello\n```\n\nThen, create a file called `main.go` with the following contents:\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"log\"\n\n    \"github.com/go-kod/kod\"\n)\n\nfunc main() {\n    if err := kod.Run(context.Background(), serve); err != nil {\n        log.Fatal(err)\n    }\n}\n\n// app is the main component of the application. kod.Run creates\n// it and passes it to serve.\ntype app struct{\n    kod.Implements[kod.Main]\n}\n\n// serve is called by kod.Run and contains the body of the application.\nfunc serve(context.Context, *app) error {\n    fmt.Println(\"Hello\")\n    return nil\n}\n```\n\n`kod.Run(...)` initializes and runs the Kod application. In particular, `kod.Run` finds the main component, creates it, and passes it to a supplied function. In this example, `app` is the main component since it contains a `kod.Implements[kod.Main]` field.\n\n```bash\ngo mod tidy\nkod generate .\ngo run .\nHello\n```\n\n## FUNDAMENTALS\n\n### Components\n\nComponents are Kod's core abstraction. Concretely, a component is represented as a Go interface and corresponding implementation of that interface. Consider the following `Adder` component for example:\n\n```go\ntype Adder interface {\n    Add(context.Context, int, int) (int, error)\n}\n\ntype adder struct {\n    kod.Implements[Adder]\n}\n\nfunc (*adder) Add(_ context.Context, x, y int) (int, error) {\n    return x + y, nil\n}\n```\n\nAdder defines the component's interface, and adder defines the component's implementation. The two are linked with the embedded `kod.Implements[Adder]` field. You can call `kod.Ref[Adder].Get()` to get a caller to the Adder component.\n\n#### Implementation\n\nA component implementation must be a struct that looks like:\n\n```go\ntype foo struct{\n    kod.Implements[Foo]\n    // ...\n}\n```\n\nIt must be a struct.\nIt must embed a `kod.Implements[T]` field where T is the component interface it implements.\nIf a component implementation implements an `Init(context.Context) error` method, it will be called when an instance of the component is created.\n\n```go\nfunc (f *foo) Init(context.Context) error {\n    // ...\n}\n\nfunc (f *foo) Shutdown(context.Context) error {\n    // ...\n}\n```\n\n#### Lazy Initialization\n\nComponents can be lazily initialized by embedding a `kod.LazyInit` field in the component implementation, \nwhich will be initialized when the component is first used, instead of when the application starts.\n\nSimple demo below:\n\n```go\ntype foo struct {\n    kod.Implements[Foo]\n    kod.LazyInit\n}\n```\n\n#### Interceptors\n\nKod has built-in common interceptors, and components can implement the following methods to inject these interceptors into component methods:\n\n```go\nfunc (f *foo) Interceptors() []interceptor.Interceptor {\n    return []interceptor.Interceptor{\n        kmetric.New(),\n        ktrace.New(),\n    }\n}\n```\n\n#### Interfaces\n\nInterface can be generated automatically by kod tool.\n\n```go\n//go:generate kod struct2interface .\n```\n\n### Config\n\n#### WithConfig\n\nKod uses config files, written in TOML, to configure how applications are run. A minimal config file, for example, simply lists the application name:\n\n```toml\n[kod]\nname = \"hello\"\n```\n\nA config file may also contain component-specific configuration sections, which allow you configuring the components in your application. For example, consider the following `Greeter` component.\n\n```go\ntype Greeter interface {\n    Greet(context.Context, string) (string, error)\n}\n\ntype greeter struct {\n    kod.Implements[Greeter]\n}\n\nfunc (g *greeter) Greet(_ context.Context, name string) (string, error) {\n    return fmt.Sprintf(\"Hello, %s!\", name), nil\n}\n```\n\nRather than hard-coding the greeting \"Hello\", we can provide a greeting in a config file. First, we define an `options` struct.\n\n```go\ntype greeterOptions struct {\n    Greeting string\n}\n```\n\nNext, we associate the `options` struct with the greeter implementation by embedding the `kod.WithConfig[T]` struct.\n\n```go\ntype greeter struct {\n    kod.Implements[Greeter]\n    kod.WithConfig[greeterOptions]\n}\n```\n\nNow, we can add a Greeter section to the config file. The section is keyed by the full path-prefixed name of the component.\n\n```toml\n[\"example.com/mypkg/Greeter\"]\nGreeting = \"Bonjour\"\n```\n\nWhen the Greeter component is created, Kod will automatically parse the Greeter section of the config file into a `greeterOptions` struct. You can access the populated struct via the `Config` method of the embedded `WithConfig` struct. For example:\n\n```go\nfunc (g *greeter) Greet(_ context.Context, name string) (string, error) {\n    greeting := g.Config().Greeting\n    if greeting == \"\" {\n        greeting = \"Hello\"\n    }\n    return fmt.Sprintf(\"%s, %s!\", greeting, name), nil\n}\n```\n\nYou can use TOML struct tags to specify the name that should be used for a field in a config file. For example, we can change the `greeterOptions` struct to the following.\n\n```go\ntype greeterOptions struct {\n    Greeting string `toml:\"my_custom_name\"`\n}\n```\n\n#### WithGlobalConfig\n\nAlso, we can use the `kod.WithGlobalConfig` struct to read the whole config from the config file.\n\n```go\ntype greeter struct {\n    kod.Implements[Greeter]\n    kod.WithGlobalConfig[greeterOptions]\n}\n```\n\nNow, we can add global configuration to the config file based on the `greeterOptions` struct.\n\n```toml\ngreeting = \"Bonjour\"\n```\n\n### Testing\n\n#### Unit Test\n\nKod includes a `Test` function that you can use to test your Kod applications. For example, create an `adder_test.go` file with the following contents.\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"testing\"\n\n    \"github.com/go-kod/kod\"\n)\n\nfunc TestAdd(t *testing.T) {\n     kod.RunTest(t, func(ctx context.Context, adder Adder) {\n         got, err := adder.Add(ctx, 1, 2)\n         if err != nil {\n             t.Fatal(err)\n         }\n         if want := 3; got != want {\n             t.Fatalf(\"got %q, want %q\", got, want)\n         }\n     })\n}\n```\n\nRun go test to run the test. `kod.RunTest` will create a sub-test and within it will create an Adder component and pass it to the supplied function. If you want to test the implementation of a component, rather than its interface, specify a pointer to the implementing struct as an argument. For example, if the `adderImpl` struct implemented the Adder interface, we could write the following:\n\n```go\nkod.RunTest(t, func(ctx context.Context, adder *adderImpl) {\n    // Test adder...\n})\n```\n\n#### Benchmark\n\nYou can also use `kod.RunTest` to benchmark your application. For example, create an adder_benchmark.go file with the following contents.\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"testing\"\n\n    \"github.com/go-kod/kod\"\n)\n\nfunc BenchmarkAdd(b *testing.B) {\n    kod.RunTest(b, func(ctx context.Context, adder Adder) {\n        b.ResetTimer()\n        for i := 0; i \u003c b.N; i++ {\n            _, err := adder.Add(ctx, 1, 2)\n            if err != nil {\n                b.Fatal(err)\n            }\n        }\n    })\n}\n```\n\n#### Fake\n\nYou can replace a component implementation with a fake implementation in a test using `kod.Fake`. Here's an example where we replace the real implementation of a Clock component with a fake implementation that always returns a fixed time.\n\n```go\n// fakeClock is a fake implementation of the Clock component.\ntype fakeClock struct {\n    now int64\n}\n\n// Now implements the Clock component interface. It returns the current time, in\n// microseconds, since the unix epoch.\nfunc (f *fakeClock) Now(context.Context) (int64, error) {\n    return f.now, nil\n}\n\nfunc TestClock(t *testing.T) {\n    t.Run(\"fake\", func(t *testing.T) {\n        // Register a fake Clock implementation with the runner.\n        fake := kod.Fake[Clock](\u0026fakeClock{100})\n\n        // When a fake is registered for a component, all instances of that\n        // component dispatch to the fake.\n        kod.RunTest(t, func(ctx context.Context, clock Clock) {\n            now, err := clock.UnixMicro(ctx)\n            if err != nil {\n                t.Fatal(err)\n            }\n            if now != 100 {\n                t.Fatalf(\"bad time: got %d, want %d\", now, 100)\n            }\n\n            fake.now = 200\n            now, err = clock.UnixMicro(ctx)\n            if err != nil {\n                t.Fatal(err)\n            }\n            if now != 200 {\n                t.Fatalf(\"bad time: got %d, want %d\", now, 200)\n            }\n        }, kod.WithFakes(fake))\n    })\n}\n```\n\n#### Config\n\nYou can also provide the contents of a config file to a runner by setting the `Runner.Config` field:\n\n```go\nfunc TestArithmetic(t *testing.T) {\n    kod.RunTest(t, func(ctx context.Context, adder Adder) {\n        // ...\n    }, kod.WithConfigFile(\"testdata/config.toml\"))\n}\n```\n\n### Logging\n\nKod provides a logging API, `kod.L`. Kod also integrates the logs into the environment where your application is deployed.\n\nUse the Logger method of a component implementation to get a logger scoped to the component. For example:\n\n```go\ntype Adder interface {\n    Add(context.Context, int, int) (int, error)\n}\n\ntype adder struct {\n    kod.Implements[Adder]\n}\n\nfunc (a *adder) Add(ctx context.Context, x, y int) (int, error) {\n    // adder embeds kod.Implements[Adder] which provides the L method.\n    logger := a.L(ctx)\n    logger.DebugContext(ctx, \"A debug log.\")\n    logger.InfoContext(ctx, \"An info log.\")\n    logger.ErrorContext(ctx, \"An error log.\", fmt.Errorf(\"an error\"))\n    return x + y, nil\n}\n```\n\n### OpenTelemetry\n\nKod relies on OpenTelemetry to collect trace and metrics from your application.\n\nSupported Environment Variables:\n\n- `OTEL_SDK_DISABLED`: If set to true, disables the OpenTelemetry SDK. Default is false.\n- `OTEL_LOGS_EXPORTER`: The logs exporter to use. Supported values are \"console\" and \"otlp\", Default is \"otlp\".\n- `OTEL_EXPORTER_OTLP_PROTOCOL`: The protocol to use for the OTLP exporter. Supported values are \"grpc\" and \"http/protobuf\", Default is \"http/protobuf\".\n- `OTEL_EXPORTER_OTLP_INSECURE`: If set to true, disables the security features of the OTLP exporter. Default is false.\n\nMore information can be found at [OpenTelemetry Website](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/).\n\n### Acknowledge\n\nThis project was heavily inspired by [ServiceWeaver](https://github.com/ServiceWeaver/weaver).\n\n## Star History\n\n\u003ca\u003e\n  \u003cpicture\u003e\n    \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://api.star-history.com/svg?repos=go-kod/kod\u0026type=Timeline\u0026theme=dark\" /\u003e\n    \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://api.star-history.com/svg?repos=go-kod/kod\u0026type=Timeline\" /\u003e\n    \u003cimg alt=\"Star History Chart\" src=\"https://api.star-history.com/svg?repos=go-kod/kod\u0026type=Timeline\" /\u003e\n  \u003c/picture\u003e\n\u003c/a\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgo-kod%2Fkod","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgo-kod%2Fkod","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgo-kod%2Fkod/lists"}