Skip to content

Cheat Sheet ​

Quickly find common APIs and code snippets.

Path Queries ​

OperationFunctionExample
Get a stringGetStringjson.GetString(data, "user.name")
Get an integerGetIntjson.GetInt(data, "count")
Get a floatGetFloatjson.GetFloat(data, "price")
Get a booleanGetBooljson.GetBool(data, "enabled")
Get an arrayGetArrayjson.GetArray(data, "items")
Get an objectGetObjectjson.GetObject(data, "user")
Get any valueGetjson.Get(data, "items[0].id")
Generic getGetTyped[T]json.GetTyped[User](data, "user")
Safe get (no panic)SafeGetjson.SafeGet(data, "user.age")
Batch getGetMultiplejson.GetMultiple(data, []string{"a", "b"})
Cancellable getGetWithContextjson.GetWithContext(ctx, data, "user.name")

With Default Values ​

GetString, GetInt, GetFloat, GetBool, and friends accept an optional default-value parameter:

OperationFunctionExample
StringGetStringjson.GetString(data, "name", "unknown")
IntegerGetIntjson.GetInt(data, "count", 0)
FloatGetFloatjson.GetFloat(data, "rate", 0.5)
BooleanGetBooljson.GetBool(data, "debug", false)

Modification Operations ​

OperationFunctionExample
Set a valueSetjson.Set(data, "user.name", "Alice")
Batch setSetMultiplejson.SetMultiple(data, map[string]any{"a": 1, "b": 2})
Set with path creationSetCreatejson.SetCreate(data, "a.b.c", 1)
Batch set with path creationSetMultipleCreatejson.SetMultipleCreate(data, updates)
Delete a valueDeletejson.Delete(data, "user.temporary")
Delete and clean upDeleteCleanjson.DeleteClean(data, "user.temporary")
go
// Set a value
result, err := json.Set(`{"user":{}}`, "user.name", "Alice")
// {"user":{"name":"Alice"}}

// Set multiple fields one at a time
result, err = json.Set(data, "user.name", "Bob")
result, err = json.Set(result, "user.age", 25)

// Delete
result, err = json.Delete(data, "user.temporary")

Batch Operations (multiple operation kinds in one call) ​

go
data := `{"user":{"name":"Alice","temp":true}}`

results, err := json.ProcessBatch([]json.BatchOperation{
    {ID: "n", Type: "get", JSONStr: data, Path: "user.name"},
    {ID: "a", Type: "set", JSONStr: data, Path: "user.age", Value: 30},
    {ID: "d", Type: "delete", JSONStr: data, Path: "user.temp"},
    {ID: "v", Type: "validate", JSONStr: data},
})
if err != nil {
    panic(err)
}
for _, r := range results {
    fmt.Println(r.ID, r.Result, r.Error)
}

TIP

BatchOperation.Type supports the four kinds get / set / delete / validate, each operation carrying its data via JSONStr; BatchResult returns Result and Error keyed by ID. See Batch Operations.

Serialization and Encoding ​

OperationFunctionExample
Encode ([]byte output)Marshaljson.Marshal(data)
Encode (string output)Encodejson.Encode(data)
Pretty encoding ([]byte)MarshalIndentjson.MarshalIndent(data, "", " ")
Pretty encoding (string)EncodePrettyjson.EncodePretty(data)
DecodeUnmarshaljson.Unmarshal(bytes, &v)
ParseParsevar v T; json.Parse(jsonStr, &v)
Parse into anyParseAnyjson.ParseAny(jsonStr)
Pretty-print JSON textPrettifyjson.Prettify(jsonStr)
Compact JSON text (buffer)Compactjson.Compact(&buf, []byte(data))
Compact JSON text (string)CompactStringjson.CompactString(jsonStr)
Re-indentIndentjson.Indent(&buf, src, "", " ")
HTML-escapeHTMLEscapejson.HTMLEscape(&buf, src)
Encode key-value pairs into an objectEncodeBatchjson.EncodeBatch(map[string]any{"a": 1})
Encode selected fieldsEncodeFieldsjson.EncodeFields(user, []string{"name"})
Encode a value list into an arrayEncodeStreamjson.EncodeStream([]any{1, 2})

json.EncodeWithConfig is deprecated (equivalent to Encode; retained within v1) — use Encode or Marshal in new code. For detailed formatting-function choices see Formatted Output.

go
// Encode
b, err := json.Marshal(map[string]any{"name": "test"})

// Pretty output
pretty, err := json.MarshalIndent(data, "", "  ")

// Parse into a map
var result map[string]any
err = json.Parse(`{"name": "test"}`, &result)

// Parse into any
parsed, err := json.ParseAny(`{"name": "test"}`)

// Pretty-print a JSON string
pretty, err = json.Prettify(`{"name":"Alice","age":30}`)

File Reading and Writing ​

OperationFunctionExample
Read a JSON file as textLoadFromFilejson.LoadFromFile("config.json")
Read from any ReaderLoadFromReaderjson.LoadFromReader(resp.Body)
Write a value to a fileSaveToFilejson.SaveToFile("out.json", data)
Encode and write to a fileMarshalToFilejson.MarshalToFile("out.json", v)
Read a file and decodeUnmarshalFromFilejson.UnmarshalFromFile("in.json", &v)
Write a value to a WriterSaveToWriterjson.SaveToWriter(w, data)
go
// Read and query
data, err := json.LoadFromFile("config.json")
if err != nil {
    panic(err)
}
env := json.GetString(data, "env", "dev")

// One step into a struct
var cfg Config
if err := json.UnmarshalFromFile("config.json", &cfg); err != nil {
    panic(err)
}

TIP

File paths go through security validation (rejecting directory traversal and symlink attacks); untrusted paths are intercepted too. See File I/O.

Validation ​

OperationFunctionExample
Quick validationValidjson.Valid([]byte(data))
Validate and get the reasonValidWithConfigjson.ValidWithConfig(data)
Schema validationValidateSchemajson.ValidateSchema(data, schema)
go
// Quick validation
if json.Valid([]byte(data)) {
    // Valid JSON
}

// When the failure reason is needed
ok, err := json.ValidWithConfig(data)
if !ok {
    fmt.Println("Invalid JSON:", err)
}

// Schema validation
schema := &json.Schema{
    Type:     "object",
    Required: []string{"name"},
    Properties: map[string]*json.Schema{
        "name": {Type: "string"},
        "age":  {Type: "number"},
    },
}
p, err := json.New()
if err != nil {
    panic(err)
}
errors, _ := p.ValidateSchema(data, schema)

Utility Functions ​

OperationFunctionExample
CompareCompareJSONjson.CompareJSON(a, b)
MergeMergeJSONjson.MergeJSON(a, b)
Merge manyMergeManyjson.MergeMany([]string{s1, s2, s3})
go
// Compare (ignoring key order and numeric precision)
equal, _ := json.CompareJSON(`{"a":1.0,"b":2}`, `{"b":2,"a":1}`)
fmt.Println("Equal:", equal) // true (order and precision ignored)

// Merge JSON
base := `{"database":{"host":"localhost","port":5432},"debug":false}`
override := `{"database":{"host":"prod-server","ssl":true},"monitoring":true}`

// Merge
merged, _ := json.MergeJSON(base, override)
// Result: {"database":{"host":"prod-server","port":5432,"ssl":true},"debug":false,"monitoring":true}

// Merge many
result, _ := json.MergeMany([]string{
    `{"a":1}`,
    `{"b":2}`,
    `{"c":3}`,
})

Processor Methods ​

go
// Create a processor
processor, err := json.New()
if err != nil {
    panic(err)
}
defer processor.Close()

// Get a value
result := processor.GetString(data, "user.profile.name")

// Safe get (returns an AccessResult)
accessResult := processor.SafeGet(data, "user.age")
age, err := accessResult.AsInt()

Creating with Configuration ​

go
// Default configuration
processor, err := json.New(json.DefaultConfig())

// Security configuration (for untrusted input)
processor, err = json.New(json.SecurityConfig())

// Custom configuration
cfg := json.DefaultConfig()
cfg.CreatePaths = true
processor, err = json.New(cfg)

Streaming ​

Iteration Function Family ​

OperationFunctionCharacteristics
Traverse array/objectForeachSimplest; no error return
Traverse with interruptionForeachWithErrorCallback returns error / item.Break()
Traverse at a given pathForeachWithPathThe explicit-path version of Foreach(data, path, ...)
Deep nested traversalForeachNestedRecurses all levels
Deep traversal with interruptionForeachNestedWithErrorThe error-returning version of ForeachNested
Traverse and rewriteForeachReturnReturns modified new JSON
Carries the current pathForeachWithPathAndIteratorCallback gets currentPath; can break
Raw-value traversal controlForeachWithPathAndControlCallback receives raw values; IteratorControl steers the flow
Traverse large filesForeachFileLoads the whole file first; use StreamIterator for constant memory
Traverse a path inside a fileForeachFileWithPathIterates the collection at a given path in the file (whole file loaded)
Chunked file traversalForeachFileChunkedBatched callbacks of chunkSize (file still fully loaded)
Recursive file traversalForeachFileNestedRecurses all nested structures in the file (whole file loaded)

Twelve iteration functions in total: the first eight operate on JSON strings in memory, the last four (ForeachFile*) operate on files (loaded fully before iterating, bounded by the MaxJSONSize cap).

go
data := `{"users":[{"name":"Alice"},{"name":"Bob"}]}`

// Simple traversal
err := json.ForeachWithPath(data, "users", func(key any, item *json.IterableValue) {
    fmt.Println(key, item.GetString("name"))
})

// Use the WithError variant when early termination is needed
// (returning item.Break() interrupts)
err = json.ForeachWithError(data, "users", func(key any, item *json.IterableValue) error {
    if item.GetString("name") == "Bob" {
        return item.Break() // stop iterating
    }
    return nil
})

Concurrent Processing (ParallelIterator) ​

go
items, _ := json.GetArray(`[1,2,3,4,5,6]`, ".")
it := json.NewParallelIterator(items)

// Parallel map
doubled, err := it.Map(func(i int, v any) (any, error) {
    return v.(float64) * 2, nil
})

// Parallel filter / traversal (automatic batching)
_ = it.Filter(func(i int, v any) bool { return v.(float64) > 2 })
_ = it.ForEach(func(i int, v any) error { return nil })

Streaming Iterators (StreamIterator / StreamObjectIterator) ​

go
f, _ := os.Open("huge.json")
defer f.Close()

// Stream a large array element by element
it, err := json.NewStreamIterator(f)
if err != nil {
    panic(err)
}
for it.Next() {
    val := it.Value() // per-element processing, constant memory
    _ = val
    _ = it.Index()
}
if err := it.Err(); err != nil {
    panic(err) // parse errors encountered in the stream
}

// Stream a large object key by key
oit, err := json.NewStreamObjectIterator(f)
for oit.Next() {
    fmt.Println(oit.Key(), oit.Value())
}

Processor.ForeachFile (large files) ​

go
// Process a large file
processor, err := json.New()
if err != nil {
    panic(err)
}
defer processor.Close()

err = processor.ForeachFile("large-data.json", func(key any, item *json.IterableValue) error {
    // Process the data item
    id := item.GetInt("id")
    name := item.GetString("name")
    return nil // return item.Break() to interrupt
})

NDJSON/JSONL ​

go
// Parse JSONL
results, err := json.ParseJSONL(jsonlBytes)

// Generic parsing (with StreamLinesInto)
file, _ := os.Open("data.jsonl")
defer file.Close()
users, err := json.StreamLinesInto[User](file, func(lineNum int, user User) error {
    return nil
})

// Streaming write
outputFile, _ := os.Create("output.jsonl")
defer outputFile.Close()
writer := json.NewJSONLWriter(outputFile)
_ = writer.Write(map[string]any{"name": "Alice"})
_ = writer.Write(map[string]any{"name": "Bob"})

// Multi-worker parallel line-by-line processing
err = json.StreamJSONLParallel(file, 4, func(lineNum int, item *json.IterableValue) error {
    return nil
})

// NDJSONProcessor: line numbers, per-object callbacks (deprecated; use the StreamJSONL family in new code)
np := json.NewNDJSONProcessor()
err = np.ProcessFile("events.ndjson", func(lineNum int, obj map[string]any) error {
    fmt.Println(lineNum, obj)
    return nil
})

Configuration Options ​

go
// Recommended: start from the default configuration and modify
cfg := json.DefaultConfig()
cfg.MaxJSONSize = 50 * 1024 * 1024 // Custom size limit (validation range 1MB-100MB; larger values are clamped back to 100MB)
cfg.FullSecurityScan = true        // Enable full security scanning

Configuration Presets ​

go
// Default configuration
cfg := json.DefaultConfig()

// Security configuration (for untrusted input)
// cfg = json.SecurityConfig()

// Pretty-print configuration
// cfg = json.PrettyConfig()

Path Syntax ​

SyntaxDescriptionExample
.propertyProperty accessuser.name
[n]Array indexitems[0]
[*]Wildcarditems[*].id
[start:end]Sliceitems[0:5]
[start:end:step]Stepped sliceitems[0:10:2]
{field1,field2}Field extractionuser{name,email}
{flat:field}Flat extractiongroups{flat:tags}
[+]Appenditems[+]
[-1]Negative index (last)items[-1]
/key/keyJSON Pointer (RFC 6901)/user/name

Common Patterns ​

Safely Getting Nested Values ​

go
// Use getters with default values
name := json.GetString(data, "user.profile.name", "unknown")

// Use Get when error types must be distinguished
val, err := json.Get(data, "user.profile.name")
if err != nil {
    if errors.Is(err, json.ErrPathNotFound) {
        // Key does not exist
    } else if errors.Is(err, json.ErrInvalidJSON) {
        // Malformed JSON
    }
    // Other errors (type conflicts, limit overruns) are contextual
    // JsonsError values — just log them
}

Getting with Default Values ​

go
// GetString/GetInt and friends accept an optional default parameter
timeout := json.GetInt(data, "timeout", 30)
debug := json.GetBool(data, "debug", false)
name := json.GetString(data, "user.nickname", "unknown")

Type Assertion ​

go
val, _ := json.Get(data, "value")
switch v := val.(type) {
case string:
    fmt.Println("string:", v)
case float64:
    fmt.Println("number:", v)
case bool:
    fmt.Println("boolean:", v)
case []any:
    fmt.Println("array:", len(v), "elements")
case map[string]any:
    fmt.Println("object:", len(v), "keys")
}

Read File → Modify Field → Write Back ​

Set returns a new string, and SaveToFile parses a JSON string before encoding (no double quoting); combined with PrettyConfig the file stays readable:

go
package main

import (
	"fmt"

	"github.com/cybergodev/json"
)

func main() {
	data, err := json.LoadFromFile("config.json")
	if err != nil {
		panic(err)
	}

	updated, err := json.Set(data, "server.port", 8080)
	if err != nil {
		panic(err)
	}

	if err := json.SaveToFile("config.json", updated, json.PrettyConfig()); err != nil {
		panic(err)
	}
	fmt.Println("Updated")
}

Batch Field Extraction from an API Response ​

A single field can be collected with a wildcard; multiple distinct paths go through GetMultiple (parses only once):

go
resp := `{"code":0,"data":{"users":[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]}}`

// Single field: collect with a wildcard
names, _ := json.GetArray(resp, "data.users[*].name") // ["Alice", "Bob"]

// Multiple distinct paths: one parse, batch retrieval
vals, err := json.GetMultiple(resp, []string{"code", "data.users[0].id"})
if err != nil {
    panic(err)
}
fmt.Println(names, vals["data.users[0].id"]) // [Alice Bob] 1

Per-Element Rewriting (ForeachReturn) ​

Inside the callback, item.GetData() yields a reference to the working copy; mutating map/slice contents is reflected in the returned new JSON (ForeachReturn iterates the root container):

go
data := `[{"name":"Alice","active":false},{"name":"Bob","active":false}]`

updated, err := json.ForeachReturn(data, func(key any, item *json.IterableValue) {
	m, ok := item.GetData().(map[string]any)
	if !ok {
		return
	}
	m["active"] = true
})
if err != nil {
	panic(err)
}
// Both elements' active becomes true (output field order may differ from the source)

Scalars cannot be replaced in place

The GetData() reference trick suits mutating map fields and array elements; when a whole element is a scalar it cannot be replaced in place via IterableValue — use Set(data, "items[*]", v) or per-item Set instead.

Config Merging ​

go
// Default config + user config
defaults := `{"timeout": 30, "retries": 3}`
userConfig := `{"timeout": 60, "debug": true}`

merged, _ := json.MergeJSON(defaults, userConfig)
// {"timeout": 60, "retries": 3, "debug": true}

Error Handling ​

go
val, err := json.Get(data, path)
if err != nil {
    // Common sentinels: key missing / malformed JSON / size limit / depth limit
    // (type conflicts return a descriptive JsonsError, not the ErrTypeMismatch sentinel)
    switch {
    case errors.Is(err, json.ErrPathNotFound):
    case errors.Is(err, json.ErrInvalidJSON):
    case errors.Is(err, json.ErrSizeLimit):
    case errors.Is(err, json.ErrDepthLimit):
    default:
        // Log the full error (includes operation name and path)
        fmt.Println(err)
    }

    // When returning to a client, sanitize with SafeError to avoid leaking
    // paths and internal details
    _ = json.SafeError(err)
}

Cache Management ​

go
// Warm up the cache
paths := []string{"user.name", "user.email", "items[*].id"}
result, _ := json.WarmupCache(data, paths)
fmt.Printf("Warm-up succeeded: %d/%d\n", result.Successful, result.TotalPaths)

// Clear the cache
json.ClearCache()

// Get statistics
stats := json.GetStats()
fmt.Printf("Cache hit ratio: %.2f%%\n", stats.HitRatio * 100)

// Health check (per-item checks of cache, memory, etc.)
health := json.GetHealthStatus()
fmt.Println("Healthy:", health.Healthy)

Global Processor ​

go
// Set a custom global processor
cfg := json.SecurityConfig()
p, err := json.New(cfg)
if err != nil {
    panic(err)
}
json.SetGlobalProcessor(p)

// Every package-level function now uses this processor
name := json.GetString(data, "user.name")

// Clean up when the application exits
defer json.ShutdownGlobalProcessor()

Security and Extensions ​

go
// Dangerous-pattern management (<script>, javascript:, etc. blocked by default)
for _, p := range json.ListDangerousPatterns() {
    fmt.Println(p.Pattern, p.Level) // Pattern is substring matching; Level is the severity
}

// Register a custom pattern (substring match, three-level handling):
//   PatternLevelCritical always blocks / Warning blocks in strict mode / Info logs only
json.RegisterDangerousPattern(json.DangerousPattern{
    Pattern: "eval(",
    Name:    "disable eval calls",
    Level:   json.PatternLevelCritical,
})

// Unregister by the Pattern string
json.UnregisterDangerousPattern("eval(")

// Hook factories: logging / timing / error transformation / input validation
p, _ := json.New()
p.AddHook(json.LoggingHook(slog.Default()))
p.AddHook(json.ErrorHook(func(ctx json.HookContext, err error) error {
    return fmt.Errorf("op %s: %w", ctx.Operation, err)
}))
p.AddHook(json.ValidationHook(func(jsonStr, path string) error {
    return nil // return non-nil to reject this input
}))

// Config chained methods
cfg := json.SecurityConfig()
cfg.AddHook(json.LoggingHook(slog.Default()))
cfg.AddDangerousPattern(json.DangerousPattern{Pattern: "exec("})
if err := cfg.Validate(); err != nil {
    panic(err) // Config self-check surfaces out-of-range values early
}
clone := cfg.Clone() // Deep copy, safe to share

See Also ​