Documentation
¶
Overview ¶
Package json provides JSON serialization capabilities for errx errors.
This package extends errx with JSON serialization while keeping the core errx package minimal and zero-dependency. It serializes all errx error types including sentinels, displayable errors, attributed errors, and stack traces.
Basic Usage ¶
err := errx.Wrap("failed to process", cause, ErrNotFound)
jsonBytes, err := json.Marshal(err)
Pretty Printing ¶
jsonBytes, err := json.MarshalIndent(err, "", " ")
Configuration ¶
jsonBytes, err := json.Marshal(err,
json.WithMaxDepth(16),
json.WithMaxStackFrames(10))
Example (ApiResponse) ¶
Example_apiResponse demonstrates using JSON serialization for API responses
package main
import (
"fmt"
"github.com/go-extras/errx"
errxjson "github.com/go-extras/errx/json"
)
var ErrNotFound = errx.NewSentinel("not found")
func main() {
// Simulate an error from the service layer
displayErr := errx.NewDisplayable("User not found")
attrErr := errx.Attrs("user_id", "12345")
serviceErr := errx.Classify(displayErr, ErrNotFound, attrErr)
// Serialize for API response
jsonBytes, _ := errxjson.MarshalIndent(serviceErr, "", " ")
fmt.Println(string(jsonBytes))
}
Output: { "message": "User not found", "display_text": "User not found", "sentinels": [ "not found" ], "attributes": [ { "key": "user_id", "value": "12345" } ], "cause": { "message": "User not found", "display_text": "User not found" } }
Example (AttributedError) ¶
Example_attributedError demonstrates serializing errors with attributes
package main
import (
"errors"
"fmt"
"github.com/go-extras/errx"
errxjson "github.com/go-extras/errx/json"
)
var ErrDatabase = errx.NewSentinel("database")
func main() {
attrErr := errx.Attrs(
"user_id", 12345,
"action", "delete",
"resource", "account",
)
err := errx.Classify(errors.New("operation failed"), attrErr, ErrDatabase)
jsonBytes, _ := errxjson.MarshalIndent(err, "", " ")
fmt.Println(string(jsonBytes))
}
Output: { "message": "operation failed", "sentinels": [ "database" ], "attributes": [ { "key": "user_id", "value": 12345 }, { "key": "action", "value": "delete" }, { "key": "resource", "value": "account" } ], "cause": { "message": "operation failed" } }
Example (ComplexError) ¶
Example_complexError demonstrates serializing errors with all features
package main
import (
"errors"
"fmt"
"github.com/go-extras/errx"
errxjson "github.com/go-extras/errx/json"
"github.com/go-extras/errx/stacktrace"
)
var ErrDatabase = errx.NewSentinel("database")
func main() {
// Build a rich error with all features
baseErr := errors.New("connection timeout")
displayErr := errx.NewDisplayable("Service temporarily unavailable")
attrErr := errx.Attrs("retry_count", 3, "host", "localhost")
err := stacktrace.Wrap("database query failed",
baseErr, displayErr, attrErr, ErrDatabase)
serialized := errxjson.ToSerializedError(err)
fmt.Printf("Has display text: %v\n", serialized.DisplayText != "")
fmt.Printf("Has attributes: %v\n", len(serialized.Attributes) > 0)
fmt.Printf("Has stack trace: %v\n", len(serialized.StackTrace) > 0)
fmt.Printf("Has sentinels: %v\n", len(serialized.Sentinels) > 0)
}
Output: Has display text: true Has attributes: true Has stack trace: true Has sentinels: true
Example (DisplayableError) ¶
Example_displayableError demonstrates serializing displayable errors
package main
import (
"fmt"
"github.com/go-extras/errx"
errxjson "github.com/go-extras/errx/json"
)
func main() {
displayErr := errx.NewDisplayable("Invalid email address")
err := errx.Wrap("validation failed", displayErr)
jsonBytes, _ := errxjson.MarshalIndent(err, "", " ")
fmt.Println(string(jsonBytes))
}
Output: { "message": "validation failed: Invalid email address", "display_text": "Invalid email address", "cause": { "message": "Invalid email address", "display_text": "Invalid email address" } }
Example (ErrorChain) ¶
Example_errorChain demonstrates serializing error chains
package main
import (
"errors"
"fmt"
"github.com/go-extras/errx"
errxjson "github.com/go-extras/errx/json"
)
var (
ErrNotFound = errx.NewSentinel("not found")
ErrDatabase = errx.NewSentinel("database")
)
func main() {
err1 := errors.New("root cause")
err2 := errx.Wrap("middle layer", err1, ErrDatabase)
err3 := errx.Wrap("top layer", err2, ErrNotFound)
serialized := errxjson.ToSerializedError(err3)
// Walk the chain
fmt.Println("Top:", serialized.Message)
if serialized.Cause != nil {
fmt.Println("Middle:", serialized.Cause.Message)
if serialized.Cause.Cause != nil {
fmt.Println("Root:", serialized.Cause.Cause.Message)
}
}
}
Output: Top: top layer: middle layer: root cause Middle: middle layer: root cause Root: root cause
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Marshal ¶
Marshal serializes an error to JSON bytes. It returns nil, nil for nil errors.
Example:
err := errx.Wrap("failed", cause, ErrNotFound)
jsonBytes, err := json.Marshal(err)
Example ¶
ExampleMarshal demonstrates basic JSON serialization of errx errors
package main
import (
"errors"
"fmt"
"github.com/go-extras/errx"
errxjson "github.com/go-extras/errx/json"
)
var ErrNotFound = errx.NewSentinel("not found")
func main() {
err := errx.Wrap("failed to fetch user", errors.New("connection timeout"), ErrNotFound)
jsonBytes, _ := errxjson.Marshal(err)
fmt.Println(string(jsonBytes))
}
Output: {"message":"failed to fetch user: connection timeout","sentinels":["not found"],"cause":{"message":"connection timeout"}}
func MarshalIndent ¶
MarshalIndent serializes an error to pretty-printed JSON bytes. It returns nil, nil for nil errors.
Example:
jsonBytes, err := json.MarshalIndent(err, "", " ")
Example ¶
ExampleMarshalIndent demonstrates pretty-printed JSON serialization
package main
import (
"fmt"
"github.com/go-extras/errx"
errxjson "github.com/go-extras/errx/json"
)
var ErrNotFound = errx.NewSentinel("not found")
func main() {
displayErr := errx.NewDisplayable("User not found")
err := errx.Wrap("lookup failed", displayErr, ErrNotFound)
jsonBytes, _ := errxjson.MarshalIndent(err, "", " ")
fmt.Println(string(jsonBytes))
}
Output: { "message": "lookup failed: User not found", "display_text": "User not found", "sentinels": [ "not found" ], "cause": { "message": "User not found", "display_text": "User not found" } }
Types ¶
type Option ¶
type Option func(*config)
Option is a function that configures the JSON serialization behavior.
func WithIncludeStandardErrors ¶
WithIncludeStandardErrors controls whether standard (non-errx) errors in the error chain are included in the serialized output. The default is true.
When set to false, only errx errors (those implementing errx.Classified) will be serialized in the cause chain. Standard errors will be skipped.
Example:
// Only include errx errors, skip standard errors jsonBytes, err := json.Marshal(err, json.WithIncludeStandardErrors(false))
Example ¶
ExampleWithIncludeStandardErrors demonstrates filtering error types
package main
import (
"errors"
"fmt"
"github.com/go-extras/errx"
errxjson "github.com/go-extras/errx/json"
)
var ErrDatabase = errx.NewSentinel("database")
func main() {
// Mix of errx and standard errors
stdErr := errors.New("standard error")
err := errx.Wrap("wrapper", stdErr, ErrDatabase)
// Exclude standard errors
serialized := errxjson.ToSerializedError(err, errxjson.WithIncludeStandardErrors(false))
// The standard error is skipped
fmt.Printf("Has cause: %v\n", serialized.Cause != nil)
fmt.Printf("Sentinels: %v\n", serialized.Sentinels)
}
Output: Has cause: false Sentinels: [database]
func WithMaxDepth ¶
WithMaxDepth sets the maximum depth for traversing error chains. This prevents issues with deeply nested or potentially circular error chains. The default is 32.
When the depth limit is reached, the serialized error will have a message of "(max depth reached)" and no further unwrapping will occur.
Example:
jsonBytes, err := json.Marshal(err, json.WithMaxDepth(10))
Example ¶
ExampleWithMaxDepth demonstrates limiting error chain depth
package main
import (
"errors"
"fmt"
"github.com/go-extras/errx"
errxjson "github.com/go-extras/errx/json"
)
func main() {
// Create a deep error chain
err := errors.New("level 3")
err = errx.Wrap("level 2", err)
err = errx.Wrap("level 1", err)
// Limit serialization to 2 levels
jsonBytes, _ := errxjson.Marshal(err, errxjson.WithMaxDepth(2))
fmt.Println(string(jsonBytes))
}
Output: {"message":"level 1: level 2: level 3","cause":{"message":"level 2: level 3","cause":{"message":"(max depth reached)"}}}
func WithMaxStackFrames ¶
WithMaxStackFrames sets the maximum number of stack frames to include in the serialized output. This prevents excessive JSON size when errors have deep stack traces. The default is 32.
If the stack trace has more frames than the limit, only the first N frames will be included in the serialized output.
Example:
jsonBytes, err := json.Marshal(err, json.WithMaxStackFrames(10))
Example ¶
ExampleWithMaxStackFrames demonstrates limiting stack trace frames
package main
import (
"errors"
"fmt"
errxjson "github.com/go-extras/errx/json"
"github.com/go-extras/errx/stacktrace"
)
func main() {
err := stacktrace.Wrap("operation failed", errors.New("base error"))
// Limit to 3 stack frames
serialized := errxjson.ToSerializedError(err, errxjson.WithMaxStackFrames(3))
fmt.Printf("Stack frames: %d\n", len(serialized.StackTrace))
fmt.Println("Has stack trace: true")
}
Output: Stack frames: 3 Has stack trace: true
type SerializedAttr ¶
SerializedAttr represents a single attribute key-value pair.
type SerializedError ¶
type SerializedError struct {
// Message is the error message from Error()
Message string `json:"message"`
// DisplayText contains the displayable error message if one exists
DisplayText string `json:"display_text,omitempty"`
// Sentinels lists all classification sentinel texts found in this error
Sentinels []string `json:"sentinels,omitempty"`
// Attributes contains structured key-value pairs attached to this error
Attributes []SerializedAttr `json:"attributes,omitempty"`
// StackTrace contains stack frames if a stack trace was captured
StackTrace []SerializedFrame `json:"stack_trace,omitempty"`
// Cause is the wrapped error (single unwrap)
Cause *SerializedError `json:"cause,omitempty"`
// Causes contains multiple wrapped errors (multi-error unwrap)
Causes []*SerializedError `json:"causes,omitempty"`
}
SerializedError represents the JSON structure of an errx error. It captures all aspects of an errx error including classifications, attributes, stack traces, and the error chain.
func ToSerializedError ¶
func ToSerializedError(err error, opts ...Option) *SerializedError
ToSerializedError converts an error to a SerializedError struct. It returns nil for nil errors. This is useful when you want to manipulate the structure before serializing.
Example:
serialized := json.ToSerializedError(err) // Manipulate serialized... jsonBytes, _ := json.Marshal(serialized)
Example ¶
ExampleToSerializedError demonstrates converting an error to a struct
package main
import (
"errors"
"fmt"
"github.com/go-extras/errx"
errxjson "github.com/go-extras/errx/json"
)
var ErrDatabase = errx.NewSentinel("database")
func main() {
attrErr := errx.Attrs("user_id", 42)
err := errx.Classify(errors.New("operation failed"), attrErr, ErrDatabase)
serialized := errxjson.ToSerializedError(err)
fmt.Printf("Message: %s\n", serialized.Message)
fmt.Printf("Attributes: %d\n", len(serialized.Attributes))
fmt.Printf("Sentinels: %v\n", serialized.Sentinels)
}
Output: Message: operation failed Attributes: 1 Sentinels: [database]
type SerializedFrame ¶
type SerializedFrame struct {
File string `json:"file"`
Line int `json:"line"`
Function string `json:"function"`
}
SerializedFrame represents a single stack frame.