Format-Specific Type Handling
Censor supports different output formats (TEXT and JSON), which can sometimes handle the same Go types differently. This guide explains the format-specific behavior of Censor.
TEXT vs JSON Output
The two main formats supported by Censor are:
- TEXT: Human-readable format, similar to how Go prints values with
fmt.Print()
- JSON: Structured format suitable for APIs, logs, and data interchange
Type-Specific Behavior
Strings
Strings are processed similarly in both formats, but with different outputs:
// Create a Censor instance with TEXT format.
cText := censor.New(censor.WithFormatter(censor.FormatterText))
// Create a Censor instance with JSON format.
cJSON := censor.New(censor.WithFormatter(censor.FormatterJSON))
// Process a string.
email := "user@example.com"
// TEXT output: [CENSORED].
// JSON output: "[CENSORED]". // Note the quotes for JSON strings.
Maps
Maps are represented differently in TEXT and JSON:
// Map with string keys and values.
user := map[string]string{
"id": "123",
"email": "user@example.com",
"password": "secret123",
}
// TEXT output: map[id:123 email:[CENSORED] password:[CENSORED]].
// JSON output: {"id":"123","email":"[CENSORED]","password":"[CENSORED]"}.
Maps with non-string keys are handled differently:
// Map with integer keys.
scores := map[int]int{
1: 100,
2: 200,
3: 300,
}
// TEXT output: map[1:100 2:200 3:300].
// JSON output: {"1":100,"2":200,"3":300}. // Keys are converted to strings in JSON.
Structs
Structs are displayed differently in TEXT and JSON:
type User struct {
ID string `json:"id" censor:"display"`
Email string `json:"email"`
Password string `json:"password"`
}
user := User{
ID: "123",
Email: "user@example.com",
Password: "secret123",
}
// TEXT output: {ID:123 Email:[CENSORED] Password:[CENSORED]}.
// JSON output: {"id":"123","email":"[CENSORED]","password":"[CENSORED]"}.
Note how JSON respects the json
struct tags, while TEXT uses the field names.
Time
Time values are formatted according to the configuration:
createdAt := time.Date(2023, 1, 1, 12, 0, 0, 0, time.UTC)
// Default format.
// TEXT output: 2023-01-01T12:00:00Z.
// JSON output: "2023-01-01T12:00:00Z". // JSON wraps the time string in quotes.
// With custom time format.
c := censor.New(censor.WithTimeFormat("2006-01-02"))
// TEXT output: 2023-01-01.
// JSON output: "2023-01-01".
Slices and Arrays
Slices and arrays are formatted differently:
// Slice of strings.
emails := []string{
"user1@example.com",
"user2@example.com",
"user3@example.com",
}
// TEXT output: [[CENSORED] [CENSORED] [CENSORED]].
// JSON output: ["[CENSORED]","[CENSORED]","[CENSORED]"].
// Slice of integers.
scores := []int{100, 200, 300}
// TEXT output: [100 200 300].
// JSON output: [100,200,300].
Pointers
Pointers are dereferenced in both formats:
email := "user@example.com"
emailPtr := &email
// TEXT output: [CENSORED].
// JSON output: "[CENSORED]".
// Nil pointers.
var nilPtr *string
// TEXT output: <nil>.
// JSON output: null.
nil
Values
Nil values are handled appropriately for each format:
// Nil interface.
var data interface{}
// TEXT output: <nil>.
// JSON output: null.
// Nil slice.
var slice []string
// TEXT output: [].
// JSON output: [].
JSON Struct Tags
For JSON output, Censor respects the json
struct tags:
type User struct {
ID string `json:"id" censor:"display"`
Email string `json:"email"`
Password string `json:"password"`
InternalNote string `json:"-"` // Will be omitted in JSON output
APIKey string `json:"api_key,omitempty"` // Will be omitted in JSON if empty
}
user := User{
ID: "123",
Email: "user@example.com",
Password: "secret123",
InternalNote: "This is an internal note",
// APIKey is empty, so it will be omitted with omitempty.
}
// TEXT output: {ID:123 Email:[CENSORED] Password:[CENSORED] InternalNote:[CENSORED] APIKey:}.
// JSON output: {"id":"123","email":"[CENSORED]","password":"[CENSORED]"}.
Changing Format at Runtime
You can change the output format at runtime:
package main
import (
"fmt"
"github.com/vpakhuchyi/censor"
)
func main() {
// Create a Censor instance with TEXT format.
c := censor.New(censor.WithFormatter(censor.FormatterText))
type User struct {
ID string `json:"id" censor:"display"`
Email string `json:"email"`
Password string `json:"password"`
}
user := User{
ID: "123",
Email: "user@example.com",
Password: "secret123",
}
// Process with TEXT format.
textOutput := c.Process(user)
fmt.Println("TEXT output:", textOutput)
// TEXT output: {ID:123 Email:[CENSORED] Password:[CENSORED]}.
// Change to JSON format.
c = censor.New(censor.WithFormatter(censor.FormatterJSON))
// Process with JSON format.
jsonOutput := c.Process(user)
fmt.Println("JSON output:", jsonOutput)
// JSON output: {"id":"123","email":"[CENSORED]","password":"[CENSORED]"}.
}
Complete Example
Here's a complete example showing format-specific behavior:
package main
import (
"fmt"
"time"
"github.com/vpakhuchyi/censor"
)
type Address struct {
Street string `json:"street"`
City string `json:"city"`
ZipCode string `json:"zip_code"`
}
type User struct {
ID string `json:"id" censor:"display"`
Email string `json:"email"`
Password string `json:"password"`
CreatedAt time.Time `json:"created_at"`
Address Address `json:"address"`
Tags []string `json:"tags"`
Metadata map[string]string `json:"metadata"`
}
func main() {
// Create users
user := User{
ID: "123",
Email: "user@example.com",
Password: "secret123",
CreatedAt: time.Date(2023, 1, 1, 12, 0, 0, 0, time.UTC),
Address: Address{
Street: "123 Main St",
City: "New York",
ZipCode: "10001",
},
Tags: []string{"premium", "active"},
Metadata: map[string]string{
"last_login": "2023-01-01",
"api_key": "sk_live_123456789",
},
}
// TEXT format
cText := censor.New(censor.WithFormatter(censor.FormatterText))
textOutput := cText.Process(user)
fmt.Println("TEXT output:", textOutput)
// TEXT output: {ID:123 Email:[CENSORED] Password:[CENSORED] CreatedAt:2023-01-01 12:00:00 +0000 UTC Address:{Street:[CENSORED] City:[CENSORED] ZipCode:[CENSORED]} Tags:[[CENSORED] [CENSORED]] Metadata:map[api_key:[CENSORED] last_login:[CENSORED]]}.
// JSON format
cJSON := censor.New(censor.WithFormatter(censor.FormatterJSON))
jsonOutput := cJSON.Process(user)
fmt.Println("JSON output:", jsonOutput)
// JSON output: {"id":"123","email":"[CENSORED]","password":"[CENSORED]","created_at":"2023-01-01T12:00:00Z","address":{"street":"[CENSORED]","city":"[CENSORED]","zip_code":"[CENSORED]"},"tags":["[CENSORED]","[CENSORED]"],"metadata":{"api_key":"[CENSORED]","last_login":"[CENSORED]"}}.
}
Next Steps
- Learn about Basic Types
- Check out Complex Types
- See Special Types