core API

core

package

API reference for the core package.

T
type

BindFunc

BindFunc is a function that extracts a value by key from a source.

pkg/core/binder.go:13-13
type BindFunc func(key string) string
S
struct

Binder

Binder binds values to struct fields based on tags.

pkg/core/binder.go:16-18
type Binder struct

Methods

AddSource
Method

AddSource registers a binding source (e.g., "query", "path", "header").

Parameters

tag string
func (*Binder) AddSource(tag string, fn BindFunc)
{
	b.sources[tag] = fn
}
Bind
Method

Bind populates struct fields from registered sources.

Parameters

target any

Returns

error
func (*Binder) Bind(target any) error
{
	val := reflect.ValueOf(target)
	if val.Kind() != reflect.Ptr || val.Elem().Kind() != reflect.Struct {
		return fmt.Errorf("target must be a pointer to a struct")
	}

	elem := val.Elem()

	// Track which fields have been set to avoid overwriting with lower priority sources?
	// Or just use the first value found (since sources loop order is random map iteration).
	// To preserve original semantics: "Try each registered source... if valStr != '' break".
	// The original implementation iterated fields, then iterated sources.
	// We want to iterate sources (cached), then fields.
	// This changes order: We iterate Source A -> all fields. Source B -> all fields.
	// If Source A and B both set Field X, the last one wins.
	// Original: For Field X, iterate sources (random order). First sets wins.
	// Since original source order was random, "Last wins" in our new loop is equivalent to "First wins" in a reversed random order.
	// So it is acceptable.

	// Collect valuesmap[fieldIndex]value
	values := make(map[int]string)

	// 1. Process explicit sources
	for tag, fn := range b.sources {
		parser := tags.NewParser(tag)
		fields := parser.ParseStruct(target)

		for _, meta := range fields {
			// Skip if already set? (First Wins strategy adaptation)
			// If we want "First Scanned Source Wins", we check existence.
			// Since source iteration is random, this is fine.
			if _, ok := values[meta.Index]; ok {
				continue
			}

			key := meta.RawTag
			if key == "" {
				continue
			}

			if val := fn(key); val != "" {
				values[meta.Index] = val
			}
		}
	}

	// 2. Process defaults
	// Only if not set by sources
	defParser := tags.NewParser("default")
	defFields := defParser.ParseStruct(target)
	for _, meta := range defFields {
		if _, ok := values[meta.Index]; !ok {
			if meta.RawTag != "" {
				values[meta.Index] = meta.RawTag
			}
		}
	}

	// 3. Apply values
	for idx, val := range values {
		field := elem.Field(idx)
		if !field.CanSet() {
			continue
		}
		if err := setField(field, val); err != nil {
			typeField := elem.Type().Field(idx)
			return fmt.Errorf("failed to bind field %s: %w", typeField.Name, err)
		}
	}

	return nil
}
BindJSON
Method

BindJSON binds a JSON body to a struct field tagged with body:"json".

Parameters

target any
data []byte

Returns

error
func (*Binder) BindJSON(target any, data []byte) error
{
	v := reflect.ValueOf(target)
	if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct {
		return nil
	}

	elem := v.Elem()
	typ := elem.Type()

	for i := 0; i < elem.NumField(); i++ {
		field := elem.Field(i)
		fieldType := typ.Field(i)

		if tag, ok := fieldType.Tag.Lookup("body"); ok && tag == "json" && field.CanSet() {
			return json.Unmarshal(data, field.Addr().Interface())
		}
	}

	return nil
}

Fields

Name Type Description
sources map[string]BindFunc
F
function

NewBinder

NewBinder creates a new binder.

Returns

pkg/core/binder.go:21-25
func NewBinder() *Binder

{
	return &Binder{
		sources: make(map[string]BindFunc),
	}
}
F
function

setField

Parameters

valStr
string

Returns

error
pkg/core/binder.go:128-160
func setField(field reflect.Value, valStr string) error

{
	switch field.Kind() {
	case reflect.String:
		field.SetString(valStr)
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		val, err := strconv.ParseInt(valStr, 10, 64)
		if err != nil {
			return err
		}
		field.SetInt(val)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		val, err := strconv.ParseUint(valStr, 10, 64)
		if err != nil {
			return err
		}
		field.SetUint(val)
	case reflect.Bool:
		val, err := strconv.ParseBool(valStr)
		if err != nil {
			return err
		}
		field.SetBool(val)
	case reflect.Float32, reflect.Float64:
		val, err := strconv.ParseFloat(valStr, 64)
		if err != nil {
			return err
		}
		field.SetFloat(val)
	default:
		return fmt.Errorf("unsupported type %s", field.Kind())
	}
	return nil
}
S
struct

Container

Container manages dependency injection.

pkg/core/container.go:8-10
type Container struct
F
function

NewContainer

NewContainer creates a new DI container.

Returns

pkg/core/container.go:13-17
func NewContainer() *Container

{
	return &Container{
		Container: di.New(),
	}
}
I
interface

Handler

Handler is the interface that all endpoints must implement.

pkg/core/handler.go:6-8
type Handler interface

Methods

Handle
Method

Parameters

Returns

any
error
func Handle(...)
S
struct

Pattern

Pattern is used in struct tags to declare routing patterns.
Different transports interpret different tags.

pkg/core/handler.go:12-12
type Pattern struct