Kod
A generics based dependency injection application framework for Go, supporting aspect oriented programming based on interceptors
Install / Use
/learn @go-kod/KodREADME
English • 简体中文 | Examples • Template • Extention
</div>Kod
Kod stands for Killer Of Dependency, a generics based dependency injection framework for Go.
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.

Feature
- Component Based: Kod is a component-based framework. Components are the building blocks of a Kod application.
- Configurable: Kod can use TOML/YAML/JSON files to configure how applications are run.
- Testing: Kod includes a Test function that you can use to test your Kod applications.
- Logging: Kod provides a logging API,
kod.L. Kod also integrates the logs into the environment where your application is deployed. - OpenTelemetry: Kod relies on OpenTelemetry to collect trace and metrics from your application.
- Hooks: Kod provides a way to run code when a component start or stop.
- Interceptors: Kod has built-in common interceptors, and components can implement the following methods to inject these interceptors into component methods.
- Interface Generation: Kod provides a way to generate interface from structure.
- Code Generation: Kod provides a way to generate kod related codes for your kod application.
Installation
go install github.com/go-kod/kod/cmd/kod@latest
If the installation was successful, you should be able to run kod -h:
A powerful tool for writing kod applications.
Usage:
kod [flags]
kod [command]
Available Commands:
callgraph generate kod callgraph for your kod application.
completion Generate the autocompletion script for the specified shell
generate generate kod related codes for your kod application.
help Help about any command
struct2interface generate interface from struct for your kod application.
Flags:
-h, --help help for kod
-t, --toggle Help message for toggle
-v, --version Help message for toggle
Use "kod [command] --help" for more information about a command.
Step by Step Tutorial
In 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.
Components
Kod'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.
In 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.
mkdir hello/
cd hello/
go mod init hello
Then, create a file called main.go with the following contents:
package main
import (
"context"
"fmt"
"log"
"github.com/go-kod/kod"
)
func main() {
if err := kod.Run(context.Background(), serve); err != nil {
log.Fatal(err)
}
}
// app is the main component of the application. kod.Run creates
// it and passes it to serve.
type app struct{
kod.Implements[kod.Main]
}
// serve is called by kod.Run and contains the body of the application.
func serve(context.Context, *app) error {
fmt.Println("Hello")
return nil
}
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.
go mod tidy
kod generate .
go run .
Hello
FUNDAMENTALS
Components
Components 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:
type Adder interface {
Add(context.Context, int, int) (int, error)
}
type adder struct {
kod.Implements[Adder]
}
func (*adder) Add(_ context.Context, x, y int) (int, error) {
return x + y, nil
}
Adder 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.
Implementation
A component implementation must be a struct that looks like:
type foo struct{
kod.Implements[Foo]
// ...
}
It must be a struct.
It must embed a kod.Implements[T] field where T is the component interface it implements.
If a component implementation implements an Init(context.Context) error method, it will be called when an instance of the component is created.
func (f *foo) Init(context.Context) error {
// ...
}
func (f *foo) Shutdown(context.Context) error {
// ...
}
Lazy Initialization
Components can be lazily initialized by embedding a kod.LazyInit field in the component implementation,
which will be initialized when the component is first used, instead of when the application starts.
Simple demo below:
type foo struct {
kod.Implements[Foo]
kod.LazyInit
}
Interceptors
Kod has built-in common interceptors, and components can implement the following methods to inject these interceptors into component methods:
func (f *foo) Interceptors() []interceptor.Interceptor {
return []interceptor.Interceptor{
kmetric.New(),
ktrace.New(),
}
}
Interfaces
Interface can be generated automatically by kod tool.
//go:generate kod struct2interface .
Config
WithConfig
Kod uses config files, written in TOML, to configure how applications are run. A minimal config file, for example, simply lists the application name:
[kod]
name = "hello"
A 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.
type Greeter interface {
Greet(context.Context, string) (string, error)
}
type greeter struct {
kod.Implements[Greeter]
}
func (g *greeter) Greet(_ context.Context, name string) (string, error) {
return fmt.Sprintf("Hello, %s!", name), nil
}
Rather than hard-coding the greeting "Hello", we can provide a greeting in a config file. First, we define an options struct.
type greeterOptions struct {
Greeting string
}
Next, we associate the options struct with the greeter implementation by embedding the kod.WithConfig[T] struct.
type greeter struct {
kod.Implements[Greeter]
kod.WithConfig[greeterOptions]
}
Now, we can add a Greeter section to the config file. The section is keyed by the full path-prefixed name of the component.
["example.com/mypkg/Greeter"]
Greeting = "Bonjour"
When 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:
func (g *greeter) Greet(_ context.Context, name string) (string, error) {
greeting := g.Config().Greeting
if greeting == "" {
greeting = "Hello"
}
return fmt.Sprintf("%s, %s!", greeting, name), nil
}
You 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.
type greeterOptions struct {
Greeting string `toml:"my_custom_name"`
}
WithGlobalConfig
Also, we can use the kod.WithGlobalConfig struct to read the whole config from the config file.
type greeter struct {
kod.Implements[Greeter]
kod.WithGlobalConfig[greeterOptions]
}
Now, we can add global configuration to the config file based on the greeterOptions struct.
greeting = "Bonjour"
Testing
Unit Test
Kod 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.
package main
import (
"context"
"testing"
"github.com/go-kod/kod"
)
func TestAdd(t *testing.T) {
kod.RunTest(t, func(ctx context.Context, adder Adder) {
got, err := adder.Add(ctx, 1, 2)
if err != nil {
t.Fatal(err)
}
if want := 3; got != want {
t.Fatalf("got %q, want %q", got, want)
}
})
}
Run go test to run the test. kod.RunTest will create a sub-test and within it will cre
