core
API
core
packageAPI reference for the core
package.
Imports
(7)
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
fn
BindFunc
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
field
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
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