-
Notifications
You must be signed in to change notification settings - Fork 0
FxJSON use guidelines (English)
CloudZA edited this page Aug 16, 2025
·
3 revisions
🚀 FxJSON Complete Guide (English) | 中文 Chinese
- What is FxJSON?
- Getting Started
- Core Concepts
- Basic Operations
- Advanced Features
- Performance Optimization
- Real-world Examples
- Troubleshooting
- Best Practices
FxJSON is a high-performance JSON parsing library for Go. Think of it as a turbo-charged version of the standard JSON library - it's designed to be fast, memory-efficient, and easy to use.
// Traditional way with encoding/json
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
data := []byte(`{"name":"Alice","age":30}`)
var user User
json.Unmarshal(data, &user) // Slow, lots of memory allocations
// FxJSON way - much faster!
node := fxjson.FromBytes(data)
name := node.Get("name").StringOr("Unknown") // Clean and fast
age := node.Get("age").IntOr(0) // With default values!# Just one command to get started
go get github.com/icloudza/fxjsonpackage main
import (
"fmt"
"github.com/icloudza/fxjson"
)
func main() {
// Let's parse some JSON!
jsonData := []byte(`{
"message": "Hello, World!",
"timestamp": 1234567890,
"success": true
}`)
// Create a node from JSON bytes
node := fxjson.FromBytes(jsonData)
// Extract values - it's that simple!
message := node.Get("message").StringOr("No message")
timestamp := node.Get("timestamp").IntOr(0)
success := node.Get("success").BoolOr(false)
fmt.Printf("Message: %s at time %d (success: %v)\n",
message, timestamp, success)
}A Node is the core type in FxJSON. It represents any JSON value - object, array, string, number, boolean, or null.
// A Node can be anything in JSON
jsonData := []byte(`{
"string": "Hello",
"number": 42,
"boolean": true,
"null": null,
"array": [1, 2, 3],
"object": {"nested": "value"}
}`)
node := fxjson.FromBytes(jsonData)
// Each Get() returns another Node
stringNode := node.Get("string") // Node representing "Hello"
numberNode := node.Get("number") // Node representing 42
arrayNode := node.Get("array") // Node representing [1,2,3]
objectNode := node.Get("object") // Node representing {"nested":"value"}FxJSON provides two ways to extract values:
// Method 1: Traditional with error handling
value, err := node.Get("key").String()
if err != nil {
// Handle error
value = "default"
}
// Method 2: Modern with default values (recommended!)
value := node.Get("key").StringOr("default") // Clean, simple, safeNavigate complex JSON structures easily:
jsonData := []byte(`{
"user": {
"profile": {
"address": {
"city": "Beijing"
}
}
}
}`)
node := fxjson.FromBytes(jsonData)
// Instead of multiple Get() calls
city1 := node.Get("user").Get("profile").Get("address").Get("city").StringOr("")
// Use GetPath() for cleaner code
city2 := node.GetPath("user.profile.address.city").StringOr("")
// Access array elements in paths
jsonData2 := []byte(`{"users": [{"name": "Alice"}, {"name": "Bob"}]}`)
node2 := fxjson.FromBytes(jsonData2)
secondUser := node2.GetPath("users[1].name").StringOr("") // "Bob"// Sample data: user information
userJSON := []byte(`{
"id": 12345,
"username": "alice_wonder",
"email": "alice@example.com",
"profile": {
"firstName": "Alice",
"lastName": "Wonder",
"age": 28,
"interests": ["coding", "reading", "hiking"]
},
"settings": {
"theme": "dark",
"notifications": true,
"language": "en"
}
}`)
user := fxjson.FromBytes(userJSON)
// Basic field access
username := user.Get("username").StringOr("anonymous")
email := user.Get("email").StringOr("")
// Nested field access
firstName := user.Get("profile").Get("firstName").StringOr("")
// Or use path for cleaner code
lastName := user.GetPath("profile.lastName").StringOr("")
// Check if fields exist
if user.HasKey("email") {
fmt.Println("User has email")
}
// Get all keys from an object
settingsKeys := user.Get("settings").GetAllKeys()
// Result: ["theme", "notifications", "language"]
// Convert to Go map for easier manipulation
settingsMap := user.Get("settings").ToMap()
for key, value := range settingsMap {
fmt.Printf("%s: %v\n", key, value.Raw())
}// Sample data: shopping cart
cartJSON := []byte(`{
"items": [
{"id": 1, "name": "Laptop", "price": 999.99, "qty": 1},
{"id": 2, "name": "Mouse", "price": 29.99, "qty": 2},
{"id": 3, "name": "Keyboard", "price": 79.99, "qty": 1}
],
"discounts": [10, 15, 5],
"tags": ["electronics", "computers", "accessories"]
}`)
cart := fxjson.FromBytes(cartJSON)
items := cart.Get("items")
// Get array length
itemCount := items.Len() // 3
// Access by index
firstItem := items.Index(0)
firstItemName := firstItem.Get("name").StringOr("")
// Iterate through array - the fast way!
var totalPrice float64
items.ArrayForEach(func(index int, item fxjson.Node) bool {
price := item.Get("price").FloatOr(0)
qty := item.Get("qty").IntOr(1)
totalPrice += price * float64(qty)
fmt.Printf("Item %d: %s - $%.2f x %d\n",
index+1,
item.Get("name").StringOr(""),
price, qty)
return true // continue iteration
})
// Array operations
discounts := cart.Get("discounts")
firstDiscount := discounts.First() // First element
lastDiscount := discounts.Last() // Last element
topTwo := discounts.Slice(0, 2) // First two elements
// Convert to Go slice
if discountSlice, err := discounts.ToIntSlice(); err == nil {
maxDiscount := int64(0)
for _, d := range discountSlice {
if d > maxDiscount {
maxDiscount = d
}
}
fmt.Printf("Max discount: %d%%\n", maxDiscount)
}// Mixed type JSON
mixedJSON := []byte(`{
"string": "hello",
"integer": 42,
"float": 3.14,
"boolean": true,
"null": null,
"array": [1, 2, 3],
"object": {"key": "value"}
}`)
node := fxjson.FromBytes(mixedJSON)
// Check types before conversion
fields := []string{"string", "integer", "float", "boolean", "null", "array", "object"}
for _, field := range fields {
n := node.Get(field)
// Multiple ways to check type
switch {
case n.IsString():
fmt.Printf("%s is a string: %s\n", field, n.StringOr(""))
case n.IsNumber():
// Numbers can be int or float
if n.IsInteger() {
fmt.Printf("%s is an integer: %d\n", field, n.IntOr(0))
} else {
fmt.Printf("%s is a float: %.2f\n", field, n.FloatOr(0))
}
case n.IsBool():
fmt.Printf("%s is a boolean: %v\n", field, n.BoolOr(false))
case n.IsNull():
fmt.Printf("%s is null\n", field)
case n.IsArray():
fmt.Printf("%s is an array with %d items\n", field, n.Len())
case n.IsObject():
fmt.Printf("%s is an object with keys: %v\n", field, n.GetAllKeys())
}
}
// Safe type conversion with defaults
anyValue := node.Get("unknown_field")
safeString := anyValue.StringOr("default") // Won't panic
safeInt := anyValue.IntOr(0) // Safe with default
safeFloat := anyValue.FloatOr(0.0) // Always safe
safeBool := anyValue.BoolOr(false) // No errors!// User registration data
registrationJSON := []byte(`{
"email": "user@example.com",
"alternativeEmail": "invalid-email",
"website": "https://example.com",
"ipAddress": "192.168.1.100",
"phone": "+1234567890",
"userId": "550e8400-e29b-41d4-a716-446655440000"
}`)
reg := fxjson.FromBytes(registrationJSON)
// Email validation
if reg.Get("email").IsValidEmail() {
fmt.Println("✅ Primary email is valid")
}
if !reg.Get("alternativeEmail").IsValidEmail() {
fmt.Println("❌ Alternative email is invalid")
}
// URL validation
if reg.Get("website").IsValidURL() {
fmt.Println("✅ Website URL is valid")
}
// IP address validation
if reg.Get("ipAddress").IsValidIPv4() {
fmt.Println("✅ IPv4 address is valid")
}
// Phone validation (E.164 format)
if reg.Get("phone").IsValidPhone() {
fmt.Println("✅ Phone number is valid")
}
// UUID validation
if reg.Get("userId").IsValidUUID() {
fmt.Println("✅ User ID is a valid UUID")
}
// Custom validation logic
password := reg.Get("password").StringOr("")
if len(password) < 8 {
fmt.Println("❌ Password too short")
}// Order data with many fields
orderJSON := []byte(`{
"order": {
"id": "ORD-2024-001",
"customer": {
"id": "CUST-123",
"name": "John Doe",
"email": "john@example.com",
"phone": "+1234567890",
"address": {
"street": "123 Main St",
"city": "New York",
"country": "USA"
}
},
"items": [
{"sku": "LAPTOP-01", "qty": 1, "price": 999.99},
{"sku": "MOUSE-02", "qty": 2, "price": 29.99}
],
"totals": {
"subtotal": 1059.97,
"tax": 95.40,
"shipping": 15.00,
"total": 1170.37
}
}
}`)
order := fxjson.FromBytes(orderJSON)
// Get multiple values at once - super efficient!
values := order.GetMultiple(
"order.id",
"order.customer.name",
"order.customer.email",
"order.totals.total",
)
// Extract all values with defaults
orderId := values[0].StringOr("N/A")
customerName := values[1].StringOr("Guest")
customerEmail := values[2].StringOr("")
totalAmount := values[3].FloatOr(0.0)
fmt.Printf("Order %s for %s (%.2f)\n", orderId, customerName, totalAmount)
// Check if all required fields exist
requiredFields := []string{
"order.id",
"order.customer.id",
"order.customer.email",
"order.items",
"order.totals.total",
}
if order.HasAllPaths(requiredFields...) {
fmt.Println("✅ All required fields present")
} else {
fmt.Println("❌ Missing required fields")
}
// Check if customer has any contact method
contactMethods := []string{
"order.customer.email",
"order.customer.phone",
"order.customer.mobile",
"order.customer.fax",
}
if order.HasAnyPath(contactMethods...) {
fmt.Println("✅ Customer has at least one contact method")
}// Product catalog
catalogJSON := []byte(`{
"products": [
{"id": 1, "name": "Laptop", "category": "Electronics", "price": 999, "inStock": true},
{"id": 2, "name": "Desk", "category": "Furniture", "price": 299, "inStock": true},
{"id": 3, "name": "Monitor", "category": "Electronics", "price": 399, "inStock": false},
{"id": 4, "name": "Chair", "category": "Furniture", "price": 199, "inStock": true},
{"id": 5, "name": "Keyboard", "category": "Electronics", "price": 79, "inStock": true}
]
}`)
catalog := fxjson.FromBytes(catalogJSON)
products := catalog.Get("products")
// Find first electronics product
_, firstElectronics, found := products.FindInArray(func(idx int, product fxjson.Node) bool {
return product.Get("category").StringOr("") == "Electronics"
})
if found {
name := firstElectronics.Get("name").StringOr("")
price := firstElectronics.Get("price").IntOr(0)
fmt.Printf("First electronics item: %s ($%d)\n", name, price)
}
// Filter all products in stock
inStockProducts := products.FilterArray(func(idx int, product fxjson.Node) bool {
return product.Get("inStock").BoolOr(false)
})
fmt.Printf("Products in stock: %d\n", len(inStockProducts))
for _, product := range inStockProducts {
fmt.Printf("- %s\n", product.Get("name").StringOr(""))
}
// Count products under $500
affordableCount := products.CountIf(func(idx int, product fxjson.Node) bool {
return product.Get("price").IntOr(0) < 500
})
fmt.Printf("Affordable products (< $500): %d\n", affordableCount)
// Check if all products have required fields
allValid := products.AllMatch(func(idx int, product fxjson.Node) bool {
return product.HasKey("id") &&
product.HasKey("name") &&
product.HasKey("price")
})
if allValid {
fmt.Println("✅ All products have required fields")
}
// Check if any product is out of stock
hasOutOfStock := products.AnyMatch(func(idx int, product fxjson.Node) bool {
return !product.Get("inStock").BoolOr(true)
})
if hasOutOfStock {
fmt.Println("⚠️ Some products are out of stock")
}// Complex nested structure
companyJSON := []byte(`{
"company": {
"name": "TechCorp",
"departments": [
{
"name": "Engineering",
"teams": [
{
"name": "Backend",
"members": [
{"name": "Alice", "role": "Lead"},
{"name": "Bob", "role": "Senior"}
]
},
{
"name": "Frontend",
"members": [
{"name": "Charlie", "role": "Senior"},
{"name": "Diana", "role": "Junior"}
]
}
]
},
{
"name": "Marketing",
"teams": [
{
"name": "Digital",
"members": [
{"name": "Eve", "role": "Manager"}
]
}
]
}
]
}
}`)
company := fxjson.FromBytes(companyJSON)
// Walk through entire JSON structure
fmt.Println("Company Structure:")
company.Walk(func(path string, node fxjson.Node) bool {
// Only print leaf nodes (actual values)
if node.IsScalar() {
indent := strings.Count(path, ".") + strings.Count(path, "[")
fmt.Printf("%s%s = %v\n",
strings.Repeat(" ", indent),
path,
node.Raw())
}
return true // continue walking
})
// Count all employees
employeeCount := 0
company.Walk(func(path string, node fxjson.Node) bool {
if strings.Contains(path, "members[") && strings.HasSuffix(path, ".name") {
employeeCount++
}
return true
})
fmt.Printf("\nTotal employees: %d\n", employeeCount)
// Find all team names
var teamNames []string
company.Walk(func(path string, node fxjson.Node) bool {
if strings.Contains(path, "teams[") && strings.HasSuffix(path, ".name") {
if name, err := node.String(); err == nil {
teamNames = append(teamNames, name)
}
}
return true
})
fmt.Printf("Teams: %v\n", teamNames)// Article metadata
articleJSON := []byte(`{
"title": " Introduction to Go Programming ",
"slug": "intro-to-go",
"description": "Learn the BASICS of Go programming language",
"tags": "golang,programming,tutorial",
"url": "https://example.com/articles/intro-to-go",
"filename": "intro_to_go.pdf"
}`)
article := fxjson.FromBytes(articleJSON)
// String manipulation
title := article.Get("title")
trimmedTitle, _ := title.Trim() // Remove whitespace
upperTitle, _ := title.ToUpper() // Convert to uppercase
lowerTitle, _ := title.ToLower() // Convert to lowercase
fmt.Printf("Original: '%s'\n", title.StringOr(""))
fmt.Printf("Trimmed: '%s'\n", trimmedTitle)
fmt.Printf("Upper: '%s'\n", upperTitle)
fmt.Printf("Lower: '%s'\n", lowerTitle)
// String checking
url := article.Get("url")
if url.Contains("example.com") {
fmt.Println("✅ URL is from example.com")
}
if url.StartsWith("https://") {
fmt.Println("✅ URL uses HTTPS")
}
filename := article.Get("filename")
if filename.EndsWith(".pdf") {
fmt.Println("✅ File is a PDF")
}
// Working with tags
tags := article.Get("tags").StringOr("")
tagList := strings.Split(tags, ",")
fmt.Printf("Tags: %v\n", tagList)// Configuration management
defaultConfigJSON := []byte(`{
"database": {
"host": "localhost",
"port": 5432,
"name": "myapp",
"pool": 10
},
"cache": {
"enabled": true,
"ttl": 3600
},
"logging": {
"level": "info",
"format": "json"
}
}`)
userConfigJSON := []byte(`{
"database": {
"host": "db.production.com",
"port": 5432,
"user": "admin",
"password": "secret"
},
"cache": {
"ttl": 7200
}
}`)
defaultConfig := fxjson.FromBytes(defaultConfigJSON)
userConfig := fxjson.FromBytes(userConfigJSON)
// Merge configurations (user config overrides defaults)
dbDefaults := defaultConfig.Get("database")
dbUser := userConfig.Get("database")
finalDb := dbDefaults.Merge(dbUser)
// Pick only safe fields (exclude sensitive data)
safeDb := dbUser.Pick("host", "port", "name")
fmt.Println("Safe to log:", safeDb)
// Omit sensitive fields
publicDb := dbUser.Omit("password", "user")
fmt.Println("Public config:", publicDb)
// Complex merge scenario
baseSettings := fxjson.FromBytes([]byte(`{
"theme": "light",
"language": "en",
"notifications": {
"email": true,
"push": false,
"sms": false
}
}`))
userSettings := fxjson.FromBytes([]byte(`{
"theme": "dark",
"notifications": {
"push": true
}
}`))
// Merge preserves structure
finalSettings := baseSettings.Merge(userSettings)
// Result: theme="dark", language="en", notifications={email:true, push:true, sms:false}// Large dataset
largeJSON := []byte(`{
"users": [
{"id": 1, "name": "User1", "score": 85, "active": true},
{"id": 2, "name": "User2", "score": 92, "active": false},
// ... imagine thousands more ...
]
}`)
data := fxjson.FromBytes(largeJSON)
users := data.Get("users")
// DON'T do this - creates intermediate nodes
var totalScore int64
for i := 0; i < users.Len(); i++ {
user := users.Index(i) // Creates a new node each time
score := user.Get("score").IntOr(0)
totalScore += score
}
// DO this instead - zero allocations!
var betterTotalScore int64
users.ArrayForEach(func(index int, user fxjson.Node) bool {
betterTotalScore += user.Get("score").IntOr(0)
return true // Continue iteration
})
// For objects, use ForEach for maximum speed
userObj := users.Index(0)
userObj.ForEach(func(key string, value fxjson.Node) bool {
// Process each field with zero allocations
fmt.Printf("%s: %s\n", key, value.Raw())
return true
})type User struct {
ID int `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
Tags []string `json:"tags"`
Profile struct {
Bio string `json:"bio"`
Location string `json:"location"`
} `json:"profile"`
}
userJSON := []byte(`{
"id": 123,
"username": "johndoe",
"email": "john@example.com",
"tags": ["developer", "gopher"],
"profile": {
"bio": "Go enthusiast",
"location": "San Francisco"
}
}`)
// Good - Node-based decoding
node := fxjson.FromBytes(userJSON)
var user1 User
err := node.Decode(&user1)
// Better - Direct decoding
var user2 User
err = fxjson.DecodeStruct(userJSON, &user2)
// Best - Ultra-fast decoding
var user3 User
err = fxjson.DecodeStructFast(userJSON, &user3)
// Performance comparison:
// node.Decode() - 1x speed (baseline)
// DecodeStruct() - 1.5x speed
// DecodeStructFast() - 2x speedimport (
"time"
"github.com/icloudza/fxjson"
)
// Enable caching for frequently parsed JSON
cache := fxjson.NewMemoryCache(100) // Cache up to 100 items
fxjson.EnableCaching(cache)
// First parse - goes to cache
start := time.Now()
node1 := fxjson.FromBytesWithCache(userJSON, 5*time.Minute)
firstTime := time.Since(start)
// Second parse - from cache (much faster!)
start = time.Now()
node2 := fxjson.FromBytesWithCache(userJSON, 5*time.Minute)
cachedTime := time.Since(start)
fmt.Printf("First parse: %v\n", firstTime)
fmt.Printf("Cached parse: %v (%.1fx faster)\n",
cachedTime, float64(firstTime)/float64(cachedTime))
// Check cache statistics
stats := cache.Stats()
fmt.Printf("Cache hit rate: %.1f%%\n", stats.HitRate*100)
// Disable caching when done
fxjson.DisableCaching()// Typical API response
type APIResponse struct {
Success bool `json:"success"`
Data interface{} `json:"data"`
Error *string `json:"error"`
Meta struct {
Page int `json:"page"`
PerPage int `json:"per_page"`
Total int `json:"total"`
} `json:"meta"`
}
func handleAPIResponse(responseBody []byte) {
node := fxjson.FromBytes(responseBody)
// Quick success check
if !node.Get("success").BoolOr(false) {
errorMsg := node.Get("error").StringOr("Unknown error")
log.Printf("API Error: %s", errorMsg)
return
}
// Process data based on type
data := node.Get("data")
if data.IsArray() {
// Handle list response
fmt.Printf("Received %d items\n", data.Len())
data.ArrayForEach(func(i int, item fxjson.Node) bool {
// Process each item
id := item.Get("id").IntOr(0)
name := item.Get("name").StringOr("")
fmt.Printf("Item %d: %s\n", id, name)
return true
})
} else if data.IsObject() {
// Handle single item response
id := data.Get("id").IntOr(0)
fmt.Printf("Single item ID: %d\n", id)
}
// Check pagination
if node.HasKey("meta") {
currentPage := node.GetPath("meta.page").IntOr(1)
totalPages := node.GetPath("meta.total").IntOr(0) /
node.GetPath("meta.per_page").IntOr(10)
fmt.Printf("Page %d of %d\n", currentPage, totalPages)
}
}type AppConfig struct {
Server struct {
Host string
Port int
SSL bool
}
Database struct {
Driver string
Host string
Port int
Name string
User string
Password string
Pool int
}
Features map[string]bool
}
func loadConfig(env string) (*AppConfig, error) {
// Load base config
baseConfig, err := os.ReadFile("config/base.json")
if err != nil {
return nil, err
}
// Load environment-specific config
envConfig, err := os.ReadFile(fmt.Sprintf("config/%s.json", env))
if err != nil {
// Environment config is optional
envConfig = []byte("{}")
}
// Parse configs
base := fxjson.FromBytes(baseConfig)
envSpecific := fxjson.FromBytes(envConfig)
// Merge configurations
// Environment-specific values override base values
final := base.Merge(envSpecific)
// Validate required fields
requiredFields := []string{
"server.host",
"server.port",
"database.driver",
"database.host",
"database.name",
}
for _, field := range requiredFields {
if !final.HasKey(field) {
return nil, fmt.Errorf("missing required field: %s", field)
}
}
// Decode to struct
var config AppConfig
if err := final.Decode(&config); err != nil {
return nil, err
}
// Apply defaults for optional fields
if config.Database.Pool == 0 {
config.Database.Pool = 10 // Default pool size
}
if config.Server.Port == 0 {
config.Server.Port = 8080 // Default port
}
return &config, nil
}// Migrate old format to new format
func migrateUserData(oldJSON []byte) ([]byte, error) {
old := fxjson.FromBytes(oldJSON)
// Build new structure
newData := map[string]interface{}{
"version": "2.0",
"user": map[string]interface{}{
"id": old.Get("user_id").IntOr(0),
"username": old.Get("user_name").StringOr(""),
"email": old.Get("email_address").StringOr(""),
"profile": map[string]interface{}{
"firstName": old.Get("first_name").StringOr(""),
"lastName": old.Get("last_name").StringOr(""),
"avatar": old.Get("profile_pic").StringOr(""),
"bio": old.Get("about").StringOr(""),
},
"settings": map[string]interface{}{
"notifications": map[string]interface{}{
"email": old.Get("email_notifications").BoolOr(true),
"push": old.Get("push_notifications").BoolOr(false),
},
"privacy": map[string]interface{}{
"profileVisible": old.Get("public_profile").BoolOr(true),
"showEmail": old.Get("show_email").BoolOr(false),
},
},
"metadata": map[string]interface{}{
"createdAt": old.Get("created_date").StringOr(""),
"modifiedAt": old.Get("modified_date").StringOr(""),
"lastLogin": old.Get("last_login").StringOr(""),
},
},
}
// Handle arrays differently
if old.HasKey("tags") {
tags := old.Get("tags")
if tags.IsString() {
// Old format: comma-separated string
tagStr := tags.StringOr("")
newData["user"].(map[string]interface{})["tags"] = strings.Split(tagStr, ",")
} else if tags.IsArray() {
// Already in new format
if tagSlice, err := tags.ToStringSlice(); err == nil {
newData["user"].(map[string]interface{})["tags"] = tagSlice
}
}
}
// Convert back to JSON
return json.Marshal(newData)
}// Analyze JSON logs
func analyzeJSONLogs(logData []byte) {
// Assume each line is a JSON object
lines := strings.Split(string(logData), "\n")
var (
errorCount int
warnCount int
infoCount int
totalLatency float64
requests int
)
errorMessages := make(map[string]int)
for _, line := range lines {
if line == "" {
continue
}
log := fxjson.FromBytes([]byte(line))
// Count log levels
level := log.Get("level").StringOr("")
switch level {
case "ERROR":
errorCount++
// Track error messages
msg := log.Get("message").StringOr("")
errorMessages[msg]++
case "WARN":
warnCount++
case "INFO":
infoCount++
}
// Analyze performance metrics
if log.HasKey("latency") {
latency := log.Get("latency").FloatOr(0)
totalLatency += latency
requests++
}
// Check for specific patterns
if log.Get("status").IntOr(0) >= 500 {
fmt.Printf("Server error at %s: %s\n",
log.Get("timestamp").StringOr(""),
log.Get("message").StringOr(""))
}
}
// Print summary
fmt.Printf("\n=== Log Analysis Summary ===\n")
fmt.Printf("Total logs: %d\n", len(lines))
fmt.Printf("Errors: %d, Warnings: %d, Info: %d\n",
errorCount, warnCount, infoCount)
if requests > 0 {
avgLatency := totalLatency / float64(requests)
fmt.Printf("Average latency: %.2fms\n", avgLatency)
}
if len(errorMessages) > 0 {
fmt.Printf("\nTop errors:\n")
for msg, count := range errorMessages {
if count > 1 {
fmt.Printf(" - %s (occurred %d times)\n", msg, count)
}
}
}
}// Problem: Empty strings might cause issues
jsonData := []byte(`{"name": "", "description": null}`)
node := fxjson.FromBytes(jsonData)
// Solution: Always use default values
name := node.Get("name").StringOr("Anonymous")
description := node.Get("description").StringOr("No description")
// Check if truly empty
if node.Get("name").IsEmpty() {
fmt.Println("Name is empty")
}// Problem: Floating point precision
jsonData := []byte(`{"price": 19.99, "tax": 1.995}`)
node := fxjson.FromBytes(jsonData)
// Solution 1: Use FloatString() to preserve original format
priceStr, _ := node.Get("price").FloatString() // "19.99"
// Solution 2: Use proper rounding for calculations
price := node.Get("price").FloatOr(0)
tax := node.Get("tax").FloatOr(0)
total := math.Round((price+tax)*100) / 100 // Proper rounding// Problem: JSON within JSON strings
jsonData := []byte(`{
"data": "{\"nested\":\"value\",\"count\":42}"
}`)
// FxJSON automatically expands nested JSON!
node := fxjson.FromBytes(jsonData)
nested := node.Get("data").Get("nested").StringOr("") // Works!
count := node.Get("data").Get("count").IntOr(0) // 42// Problem: Processing large arrays efficiently
largeArray := []byte(`{"items": [/* thousands of items */]}`)
// Solution: Use streaming approach
node := fxjson.FromBytes(largeArray)
items := node.Get("items")
// Process in batches
batchSize := 100
for i := 0; i < items.Len(); i += batchSize {
end := i + batchSize
if end > items.Len() {
end = items.Len()
}
// Process batch
for j := i; j < end; j++ {
item := items.Index(j)
// Process item
}
// Could add sleep here to prevent overwhelming system
// time.Sleep(10 * time.Millisecond)
}// ❌ Don't do this
value, err := node.Get("key").String()
if err != nil {
// Handle error
}
// ✅ Do this instead
value := node.Get("key").StringOr("default")// ❌ Verbose and error-prone
city := node.Get("user").Get("address").Get("city").StringOr("")
// ✅ Clean and readable
city := node.GetPath("user.address.city").StringOr("")// ✅ Safe approach
field := node.Get("unknown_field")
if field.IsNumber() {
value := field.IntOr(0)
// Use value
} else if field.IsString() {
value := field.StringOr("")
// Use value
}// ✅ Always validate structure
requiredFields := []string{"id", "name", "email"}
if !node.HasAllPaths(requiredFields...) {
return errors.New("missing required fields")
}
// Then process safely
id := node.Get("id").IntOr(0)
name := node.Get("name").StringOr("")
email := node.Get("email").StringOr("")// ❌ Slow for large objects/arrays
for i := 0; i < array.Len(); i++ {
item := array.Index(i)
// Process
}
// ✅ Fast, zero-allocation
array.ArrayForEach(func(i int, item fxjson.Node) bool {
// Process
return true
})