Value Package — Type-Safe Dynamic Values¶
The value package provides a type-safe way to work with dynamic JSON-like data structures.
Overview¶
The value package contains the following core types:
| Type | Description | Use Case |
|---|---|---|
Object |
Key-value pair collection | Like JSON objects |
Array |
Ordered collection of values | Like JSON arrays |
Text |
String value | Text data |
Number |
Numeric value | Integer or float |
Bool |
Boolean value | true/false |
Any |
Any value | Non-standard types (structs, etc.) |
Null |
Null value | null |
Basic Usage¶
Creating Objects¶
import "github.com/chuccp/go-web-frame/value"
// Create empty object
obj := value.NewObject()
// Create from map
m := map[string]any{"name": "Alice", "age": 25}
obj := value.NewObjectFromMap(m)
// Create from JSON
jsonBytes := []byte(`{"name":"Alice","age":25}`)
obj, err := value.NewObjectFromJson(jsonBytes)
Setting and Getting Values¶
// Set values
obj.PutAny("name", "Alice") // Auto-converts type
obj.PutAny("age", 25)
obj.PutAny("active", true)
obj.Put("key", value.NewText("value")) // Use concrete type
// Get values
name := obj.GetString("name") // "Alice"
age := obj.GetInt("age") // 25
active := obj.GetBool("active") // true
score := obj.GetNumber("score") // 0.0 (zero value if not exists)
// Get with default values
count := obj.GetIntForDefault("count", 0) // 0 (default)
name := obj.GetStringForDefault("name", "Anonymous") // "Anonymous" (default)
// Check if key exists
if obj.HasKey("name") {
// Key exists
}
// Check key-value pair
if obj.HasKeyValue("name", "Alice") {
// Key exists and value equals "Alice"
}
Nested Objects and Arrays¶
// Create nested object
address := value.NewObject()
address.PutAny("city", "Beijing")
address.PutAny("street", "Chaoyang Road")
obj.Put("address", address)
// Get nested object
addr := obj.GetObject("address")
city := addr.GetString("city") // "Beijing"
// Create array
tags := value.NewArray(
value.NewText("go"),
value.NewText("web"),
value.NewText("framework"),
)
obj.Put("tags", tags)
// Get array
arr := obj.GetArray("tags")
arr.ForEach(func(i int, v value.Value) bool {
fmt.Println(v.String()) // go, web, framework
return true
})
Advanced Usage¶
Decoding to Struct¶
Use the Decode method to convert an Object to a Go struct:
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Email string `json:"email"`
Address struct {
City string `json:"city"`
ZipCode string `json:"zip_code"`
} `json:"address"`
}
obj := value.NewObject()
obj.PutAny("name", "Alice")
obj.PutAny("age", 25)
obj.PutAny("email", "alice@example.com")
address := value.NewObject()
address.PutAny("city", "Beijing")
address.PutAny("zip_code", "100000")
obj.Put("address", address)
var user User
err := obj.Decode(&user)
if err != nil {
log.Fatal(err)
}
fmt.Println(user.Name) // Alice
fmt.Println(user.Address.City) // Beijing
Converting to Map¶
obj := value.NewObject()
obj.PutAny("name", "Alice")
obj.PutAny("age", 25)
m := obj.ToMap()
// m = map[string]any{"name": "Alice", "age": int64(25)}
JSON Serialization¶
obj := value.NewObject()
obj.PutAny("name", "Alice")
obj.PutAny("age", 25)
// Convert to JSON
jsonBytes := obj.ToJSON()
fmt.Println(string(jsonBytes)) // {"name":"Alice","age":25}
// Implements json.Marshaler interface
data, err := json.Marshal(obj)
// Implements json.Unmarshaler interface
var obj2 value.Object
err := json.Unmarshal(data, &obj2)
Any Type¶
The Any type is used for non-standard values (like custom structs):
type Status struct {
Code int
Message string
}
obj := value.NewObject()
obj.PutAny("status", Status{Code: 200, Message: "ok"})
// Get Any value
v := obj.Get("status")
if v.IsAny() {
status := v.AsAny().Value().(Status)
fmt.Println(status.Code) // 200
}
// Any type supports JSON serialization
jsonBytes := obj.ToJSON()
// {"status":{"Code":200,"Message":"ok"}}
Iterating Over Objects¶
obj := value.NewObject()
obj.PutAny("name", "Alice")
obj.PutAny("age", 25)
obj.PutAny("city", "Beijing")
// Using ForEach
obj.ForEach(func(key string, value value.Value) bool {
fmt.Printf("%s: %v\n", key, value.String())
return true // Return false to stop iteration
})
// Using Iter (Go 1.23+)
for k, v := range obj.Iter {
fmt.Printf("%s: %v\n", k, v.String())
}
Using in Web Framework¶
JSONObject¶
JSONObject is a type alias for value.Object, widely used in web requests:
// Get JSON request body
jsonObj, err := req.Json()
if err != nil {
return nil, err
}
// Type-safe getters
name := jsonObj.GetString("name")
age := jsonObj.GetInt("age")
// Bind to struct
var input UserInput
err := req.BindJSON(&input)
// Get pagination parameters
page, err := req.JsonPage()
Comparison with KV¶
| Feature | KV | value.Object |
|---|---|---|
| Type | map[string]any |
Custom struct |
| Type safety | Runtime check | Compile-time check |
| Nested support | Manual conversion | Native support |
| JSON serialization | Standard library | Custom implementation |
| Struct decoding | Requires mapstructure | Built-in Decode method |
Best Practices¶
- Prefer structs: For known data structures, use structs instead of Object
- Use type-safe getters: Like
GetString,GetInt, avoid type assertions - Handle defaults: Use
GetXxxForDefaultmethods for potentially missing fields - Nested objects: Use
GetObjectfor nested objects, avoid type assertions - JSON tags: Use
jsontags to ensure consistency with JSON field names
Complete Example¶
package main
import (
"encoding/json"
"fmt"
"log"
"github.com/chuccp/go-web-frame/value"
)
func main() {
// Create user object
user := value.NewObject()
user.PutAny("id", 1)
user.PutAny("name", "Alice")
user.PutAny("email", "alice@example.com")
user.PutAny("active", true)
// Create address object
address := value.NewObject()
address.PutAny("city", "Beijing")
address.PutAny("street", "Chaoyang Road 123")
address.PutAny("zip_code", "100000")
user.Put("address", address)
// Create tags array
tags := value.NewArray(
value.NewText("developer"),
value.NewText("go"),
value.NewText("backend"),
)
user.Put("tags", tags)
// Get values
fmt.Printf("ID: %d\n", user.GetInt("id"))
fmt.Printf("Name: %s\n", user.GetString("name"))
fmt.Printf("Email: %s\n", user.GetString("email"))
fmt.Printf("Active: %v\n", user.GetBool("active"))
fmt.Printf("City: %s\n", user.GetObject("address").GetString("city"))
// Iterate tags
fmt.Print("Tags: ")
user.GetArray("tags").ForEach(func(i int, v value.Value) bool {
if i > 0 {
fmt.Print(", ")
}
fmt.Print(v.String())
return true
})
fmt.Println()
// Convert to JSON
jsonBytes := user.ToJSON()
fmt.Printf("JSON: %s\n", string(jsonBytes))
// Decode to struct
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Active bool `json:"active"`
Address struct {
City string `json:"city"`
Street string `json:"street"`
ZipCode string `json:"zip_code"`
} `json:"address"`
Tags []string `json:"tags"`
}
var u User
if err := user.Decode(&u); err != nil {
log.Fatal(err)
}
fmt.Printf("Decoded: %+v\n", u)
}