-
Notifications
You must be signed in to change notification settings - Fork 0
json_en.md
The json package provides advanced JSON processing capabilities for HypGo. Built on encoding/json, it integrates go-playground/validator/v10 for data validation during serialization and deserialization, and provides map/JSON conversion utilities and input sanitization functions.
-
Powerful Struct Validation: Integrates
validatorwithinValidatedUnmarshal, completing validation during parsing. -
JSON Schema Support: Provides JSON Schema-like property validation (
ValidateWithSchema), including required fields, length, regular expressions, and enum restrictions. -
Typed Unmarshal: Provides
TypedUnmarshalfor automatic type-safe conversion to match the target struct's fields. -
Unified Error Format: Automatically organizes
validator.ValidationErrorsinto structuredValidationError, making it easy for APIs to return clear error messages to the frontend. -
Custom Validation: Provides
RegisterValidationfor custom tags, allowing developers to easily extend validation logic. - Convert Utilities: Bidirectional map ↔ JSON conversion (string, bytes, formatted indent).
- Input Utilities: Built-in Email / Phone format validation and HTML input sanitization.
Create a Validator to validate required fields, email format, and more via struct tags (validate:"...") during JSON parsing:
import hypjson "github.com/maoxiaoyue/hypgo/pkg/json"
type UserRequest struct {
Name string `json:"name" validate:"required"`
Email string `json:"email" validate:"required,email"`
Age int `json:"age" validate:"min=18"`
}
v := hypjson.NewValidator()
data := []byte(`{"name": "Alice", "email": "alice@example", "age": 16}`)
var req UserRequest
err := v.ValidatedUnmarshal(data, &req)
if err != nil {
errs := v.FormatErrors(err)
for _, e := range errs {
fmt.Printf("Field %s error: %s\n", e.Field, e.Message)
}
}Parses JSON with automatic type conversion based on the target struct's field types. Returns a clear error if types are incompatible:
type Config struct {
Port int `json:"port"`
Timeout float64 `json:"timeout"`
Debug bool `json:"debug"`
}
data := []byte(`{"port": 8080, "timeout": 30.5, "debug": true}`)
var cfg Config
if err := hypjson.TypedUnmarshal(data, &cfg); err != nil {
log.Fatal(err)
}
// cfg.Port = 8080, cfg.Timeout = 30.5, cfg.Debug = trueThe difference from ValidatedUnmarshal: TypedUnmarshal does not execute validate tag checks — it focuses solely on type conversion safety.
FormatErrors converts validator.ValidationErrors into a structured []ValidationError, where each error contains the field name, validation rule, original value, and a human-readable message:
type ValidationError struct {
Field string
Tag string
Value interface{}
Message string
}
errs := v.FormatErrors(err)
for _, e := range errs {
// e.Field -> "email"
// e.Tag -> "email"
// e.Message -> "email must be a valid email address"
fmt.Printf("[%s] %s\n", e.Field, e.Message)
}Built-in message mappings:
| Tag | Message Format |
|---|---|
required |
{field} is required |
email |
{field} must be a valid email address |
min |
{field} must be at least {param} |
max |
{field} must not exceed {param} |
| others | {field} failed {tag} validation |
v := hypjson.NewValidator()
// Custom "taiwan_phone" validation rule
v.RegisterValidation("taiwan_phone", func(fl validator.FieldLevel) bool {
phone := fl.Field().String()
return strings.HasPrefix(phone, "09") && len(phone) == 10
})
type ContactForm struct {
Phone string `json:"phone" validate:"required,taiwan_phone"`
}Apply a Schema definition to dynamic or non-Go-struct-defined JSON data:
minLen := 3
maxLen := 20
schema := hypjson.Schema{
Type: "object",
Required: []string{"username"},
Properties: map[string]hypjson.Property{
"username": {
Type: "string",
MinLength: &minLen,
MaxLength: &maxLen,
},
"age": {
Type: "number",
Minimum: func() *float64 { v := 0.0; return &v }(),
Maximum: func() *float64 { v := 150.0; return &v }(),
},
"status": {
Type: "string",
Enum: []string{"active", "inactive", "pending"},
},
"email": {
Type: "string",
Pattern: `^[^@]+@[^@]+\.[^@]+$`,
},
},
}
data := []byte(`{"username": "Al", "status": "unknown"}`)
if err := hypjson.ValidateWithSchema(data, schema); err != nil {
log.Println("Schema validation failed:", err)
}Supported Property fields:
| Field | Type | Description |
|---|---|---|
Type |
string |
"string", "number", "integer", "boolean", "array", "object"
|
MinLength |
*int |
Minimum string length |
MaxLength |
*int |
Maximum string length |
Minimum |
*float64 |
Numeric lower bound |
Maximum |
*float64 |
Numeric upper bound |
Pattern |
string |
Regular expression |
Enum |
[]string |
Allowed values |
Format |
string |
Format hint (documentation only, no validation) |
type Response struct {
ID int `json:"id"`
Name string `json:"name"`
}
resp := Response{ID: 1, Name: "Alice"}
// With indentation (human-readable)
b, _ := hypjson.Marshal(resp)
fmt.Println(string(b))
// {
// "id": 1,
// "name": "Alice"
// }
// Compact format (for transport)
b, _ = hypjson.MarshalCompact(resp)
fmt.Println(string(b))
// {"id":1,"name":"Alice"}convert.go provides bidirectional map ↔ JSON conversion with five functions. A nil map always returns "null"; empty input returns an error.
m := map[string]interface{}{
"name": "Alice",
"age": 30,
"tags": []string{"admin", "user"},
}
// Compact string
s, err := hypjson.Map2JSON(m)
// -> {"age":30,"name":"Alice","tags":["admin","user"]}
// Formatted string (prefix="", indent=" ")
s, err = hypjson.Map2JSONIndent(m, "", " ")
// -> {
// "age": 30,
// "name": "Alice",
// "tags": ["admin","user"]
// }
// Compact bytes (for direct use in HTTP responses)
b, err := hypjson.Map2JSONBytes(m)Nil map behavior:
s, _ := hypjson.Map2JSON(nil) // -> "null"
b, _ := hypjson.Map2JSONBytes(nil) // -> []byte("null")// Parse from string
m, err := hypjson.JSON2Map(`{"name":"Alice","age":30}`)
// m["name"] == "Alice", m["age"] == float64(30)
// Parse from bytes
b := []byte(`{"key":"value"}`)
m, err = hypjson.JSON2MapBytes(b)Note: numeric types are uniformly float64 after JSON parsing (standard encoding/json behavior).
// Scenario: receive JSON request -> modify field -> return JSON
raw := []byte(`{"user":"alice","score":100}`)
m, err := hypjson.JSON2MapBytes(raw)
if err != nil {
return err
}
m["score"] = m["score"].(float64) + 10 // score + 10
result, err := hypjson.Map2JSON(m)
// -> {"score":110,"user":"alice"}input.go provides input format validation and XSS protection sanitization.
Validates email format using a regular expression (^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$):
hypjson.ValidateEmail("alice@example.com") // -> true
hypjson.ValidateEmail("alice@example") // -> false
hypjson.ValidateEmail("not-an-email") // -> falseValidates phone numbers in E.164 format (^\+?[1-9]\d{1,14}$):
hypjson.ValidatePhone("+886912345678") // -> true
hypjson.ValidatePhone("0912345678") // -> false (E.164 format required)
hypjson.ValidatePhone("+1-800-555") // -> falseConverts HTML special characters to HTML entities to prevent XSS injection:
raw := `<script>alert("xss")</script>`
safe := hypjson.SanitizeInput(raw)
// -> <script>alert("xss")</script>Conversion table:
| Character | Converted To |
|---|---|
< |
< |
> |
> |
" |
" |
' |
' |
Combined usage example (sanitize JSON input before storing):
type CommentRequest struct {
Content string `json:"content" validate:"required,max=500"`
}
v := hypjson.NewValidator()
var req CommentRequest
if err := v.ValidatedUnmarshal(data, &req); err != nil {
return err
}
// Sanitize user input before storing to database
req.Content = hypjson.SanitizeInput(req.Content)| Function / Method | Description |
|---|---|
NewValidator() |
Create a Validator (auto uses json tag as field name) |
v.ValidatedUnmarshal(data, dest) |
Parse JSON and run validate tag checks |
TypedUnmarshal(data, dest) |
Parse JSON with type-safe conversion (no validation) |
ValidateWithSchema(data, schema) |
Validate raw JSON against a Schema definition |
v.FormatErrors(err) |
Convert validation errors to []ValidationError
|
v.RegisterValidation(tag, fn) |
Register a custom validation rule |
Marshal(v) |
Serialize with indentation |
MarshalCompact(v) |
Serialize compact (no indentation) |
| Function | Description |
|---|---|
Map2JSON(m) |
map → JSON string (compact) |
Map2JSONIndent(m, prefix, indent) |
map → JSON string (formatted) |
Map2JSONBytes(m) |
map → JSON bytes (compact) |
JSON2Map(s) |
JSON string → map |
JSON2MapBytes(b) |
JSON bytes → map |
| Function | Description |
|---|---|
ValidateEmail(email) |
Validate email format, returns bool
|
ValidatePhone(phone) |
Validate E.164 phone format, returns bool
|
SanitizeInput(input) |
Escape HTML special characters (XSS protection) |
pkg/json/
├── validator.go # Validator, ValidatedUnmarshal, TypedUnmarshal,
│ # ValidateWithSchema, Marshal, FormatErrors, RegisterValidation
├── convert.go # Map2JSON, Map2JSONIndent, Map2JSONBytes, JSON2Map, JSON2MapBytes
├── input.go # ValidateEmail, ValidatePhone, SanitizeInput
├── validator_test.go
└── convert_test.go
由 台灣卯小月 用 ❤️ 製作 · MIT License And Wiki is written by Claude
設計文件
套件
- config — 設定
- context — 請求上下文
- router — 路由器
- server — 伺服器
- middleware — 中介層
- websocket — WebSocket
- hidb — 資料庫 ORM
- hidb/cassandra — Cassandra
- logger — 日誌
- json — JSON 處理
- grpc — gRPC
AI 協作工具鏈
- schema — Schema-first 路由
- manifest — 專案 Manifest
- contract — Contract Testing
- errors — Typed Error Catalog
- migrate — Migration Diff
- scaffold — 智慧 Scaffold
- airules — AI Rules
CLI 命令
- hyp 總覽
- hyp new
- hyp api
- hyp run
- hyp restart
- hyp generate
- hyp migrate
- hyp context
- hyp ai-rules
- hyp chkcomment
- hyp impact
- hyp docker
- hyp health
- hyp version
- hyp difflog
Design Docs
Packages
- config — Configuration
- context — Request Context
- router — Router
- server — Server
- middleware — Middleware
- websocket — WebSocket
- hidb — Database ORM
- hidb/cassandra - Cassandra 5.0
- logger — Logger
- json — JSON
- grpc — gRPC
AI Collaboration Toolchain
- schema — Schema-first Routing
- manifest — Project Manifest
- contract — Contract Testing
- errors — Typed Error Catalog
- migrate — Migration Diff
- scaffold — Smart Scaffold
- airules — AI Rules
CLI Commands