Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

json.md

maoxiaoyue edited this page May 14, 2026 · 2 revisions

JSON Package (pkg/json)

json 套件為 HypGo 提供進階 JSON 處理能力,基於 encoding/json 整合 go-playground/validator/v10,在序列化或反序列化過程中進行資料檢查與驗證,並提供 map/JSON 互轉工具及輸入清理函式。

主要特色

  • 強大的 Struct 驗證: 將 validator 內建於 ValidatedUnmarshal 中,解析即完成校驗。
  • JSON Schema 驗證: 提供像 JSON Schema 一樣的屬性驗證功能 (ValidateWithSchema),包括必填欄位、長度、正則表達式或 Enum 限定。
  • 類型自動轉型: 提供 TypedUnmarshal 自動適配目標結構體支援的類型轉換操作。
  • 統一錯誤格式: 將 validator.ValidationErrors 自動整理為結構化的 ValidationError,方便 API 將明確的錯誤訊息回傳給前端。
  • 自定義驗證: 提供 RegisterValidation 讓開發者擴充驗證邏輯。
  • Convert 工具: 提供 map ↔ JSON 雙向轉換(字串、bytes、格式化縮排)。
  • Input 工具: 內建 Email / Phone 格式驗證與 HTML 輸入清理。

Validator

結構體驗證解析

透過建立一個 Validator,在 json.Unmarshal 的當下利用 struct tag (validate:"...") 驗證必填項、Email 格式等:

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("欄位 %s 發生錯誤: %s\n", e.Field, e.Message)
 }
}

TypedUnmarshal

在解析過程中根據目標 struct 的欄位型別進行自動轉型,若型別不相容則回傳明確錯誤:

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 = true

ValidatedUnmarshal 的差異:TypedUnmarshal 不執行 validate tag 驗證,專注於型別轉換的安全性。

驗證錯誤格式

FormatErrorsvalidator.ValidationErrors 轉換為結構化的 []ValidationError,每個錯誤包含欄位名稱、驗證規則、原始值與可讀訊息:

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)
}

內建的訊息對應:

Tag 訊息格式
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}
其他 {field} failed {tag} validation

自定義驗證規則

v := hypjson.NewValidator()
// 自定義 "taiwan_phone" 驗證規則
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"`
}

JSON Schema 驗證

對動態或未定義成 Go struct 的 JSON 資料套用 Schema 定義:

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)
}

Property 支援的欄位:

欄位 型別 說明
Type string "string", "number", "integer", "boolean", "array", "object"
MinLength *int 字串最小長度
MaxLength *int 字串最大長度
Minimum *float64 數值下限
Maximum *float64 數值上限
Pattern string 正則表達式
Enum []string 允許值清單
Format string 格式提示(文件用,不做驗證)

Marshal / MarshalCompact

type Response struct {
 ID int `json:"id"`
 Name string `json:"name"`
}
resp := Response{ID: 1, Name: "Alice"}
// 帶縮排(人類可讀)
b, _ := hypjson.Marshal(resp)
fmt.Println(string(b))
// {
// "id": 1,
// "name": "Alice"
// }
// 緊湊格式(傳輸用)
b, _ = hypjson.MarshalCompact(resp)
fmt.Println(string(b))
// {"id":1,"name":"Alice"}

Convert

convert.go 提供 map ↔ JSON 雙向轉換,共五個函式。nil map 一律回傳 "null",空輸入回傳錯誤。

Map → JSON

m := map[string]interface{}{
 "name": "Alice",
 "age": 30,
 "tags": []string{"admin", "user"},
}
// 緊湊字串
s, err := hypjson.Map2JSON(m)
// → {"age":30,"name":"Alice","tags":["admin","user"]}
// 格式化字串(prefix="", indent=" ")
s, err = hypjson.Map2JSONIndent(m, "", " ")
// → {
// "age": 30,
// "name": "Alice",
// "tags": ["admin","user"]
// }
// 緊湊 bytes(直接用於 HTTP response)
b, err := hypjson.Map2JSONBytes(m)

nil map 的行為:

s, _ := hypjson.Map2JSON(nil) // → "null"
b, _ := hypjson.Map2JSONBytes(nil) // → []byte("null")

JSON → Map

// 從字串解析
m, err := hypjson.JSON2Map(`{"name":"Alice","age":30}`)
// m["name"] == "Alice", m["age"] == float64(30)
// 從 bytes 解析
b := []byte(`{"key":"value"}`)
m, err = hypjson.JSON2MapBytes(b)

注意:數值型別在 JSON 解析後統一為 float64(標準 encoding/json 行為)。

完整轉換流程範例

// 情境:接收 JSON 請求 → 修改欄位 → 回傳 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

input.go 提供輸入格式驗證與 XSS 防護清理。

ValidateEmail

使用正則表達式驗證 Email 格式(^[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") // → false

ValidatePhone

使用 E.164 格式驗證電話號碼(^\+?[1-9]\d{1,14}$):

hypjson.ValidatePhone("+886912345678") // → true
hypjson.ValidatePhone("0912345678") // → false(需 E.164 格式)
hypjson.ValidatePhone("+1-800-555") // → false

SanitizeInput

將 HTML 特殊字元轉換為 HTML entities,防止 XSS 注入:

raw := `<script>alert("xss")</script>`
safe := hypjson.SanitizeInput(raw)
// → &lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;

轉換對照:

字元 轉換後
< &lt;
> &gt;
" &quot;
' &#x27;

結合使用範例(接收 JSON 輸入後清理):

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
}
// 清理使用者輸入,再存入資料庫
req.Content = hypjson.SanitizeInput(req.Content)

函式速查

Validator

函式 / 方法 說明
NewValidator() 建立 Validator(自動以 json tag 為欄位名)
v.ValidatedUnmarshal(data, dest) 解析 JSON 並執行 validate tag 驗證
TypedUnmarshal(data, dest) 解析 JSON 並做型別安全轉換(無驗證)
ValidateWithSchema(data, schema) 用 Schema 定義驗證原始 JSON
v.FormatErrors(err) 將驗證錯誤轉為 []ValidationError
v.RegisterValidation(tag, fn) 註冊自定義驗證規則
Marshal(v) 序列化(帶縮排)
MarshalCompact(v) 序列化(緊湊,無縮排)

Convert

函式 說明
Map2JSON(m) map → JSON 字串(緊湊)
Map2JSONIndent(m, prefix, indent) map → JSON 字串(格式化)
Map2JSONBytes(m) map → JSON bytes(緊湊)
JSON2Map(s) JSON 字串 → map
JSON2MapBytes(b) JSON bytes → map

Input

函式 說明
ValidateEmail(email) 驗證 Email 格式,回傳 bool
ValidatePhone(phone) 驗證 E.164 電話格式,回傳 bool
SanitizeInput(input) HTML 特殊字元轉義(XSS 防護)

檔案結構

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

HypGo

繁體中文 | English


中文文件

設計文件

套件

AI 協作工具鏈

CLI 命令


English Docs

Design Docs

Packages

AI Collaboration Toolchain

CLI Commands

Clone this wiki locally

AltStyle によって変換されたページ (->オリジナル) /