schema.md - maoxiaoyue/hypgo GitHub Wiki
pkg/schema — Schema-first 路由註冊
讓路由攜帶 metadata(輸入/輸出型別、描述、標籤),AI 無需追蹤 handler 實作即可理解 API 行為。
設計理念
傳統路由只告訴框架「這個 URL 對應哪個 handler」,AI 必須閱讀 handler 原始碼才能理解 API。Schema-first 路由讓 metadata 直接附著在路由上:
傳統:r.POST("/api/users", createUserHandler) ← AI 需讀 handler 原始碼
Schema:r.Schema(Route{...}).Handle(handler) ← AI 直接從 metadata 理解
快速上手
import "github.com/maoxiaoyue/hypgo/pkg/schema"
// 定義請求/回應型別
type CreateUserRequest struct {
Name string `json:"name"`
Email string `json:"email"`
}
type UserResponse struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
// 註冊帶 schema 的路由
r := router.New()
r.Schema(schema.Route{
Method: "POST",
Path: "/api/users",
Summary: "建立使用者",
Tags: []string{"users"},
Input: CreateUserRequest{},
Output: UserResponse{},
Responses: map[int]schema.ResponseSchema{
201: {Description: "User created"},
400: {Description: "Invalid input"},
},
}).Handle(createUserHandler)
搭配路由群組
api := r.NewGroup("/api/v1")
api.Schema(schema.Route{
Method: "GET",
Path: "/products",
Summary: "取得商品列表",
Tags: []string{"products"},
Output: []ProductResponse{},
}).Handle(listProductsHandler)
// 路由自動註冊為 GET /api/v1/products
混合使用
Schema 路由與傳統路由可以並存,完全向後相容:
r.GET("/health", healthHandler) // 傳統路由 — 照常使用
r.Schema(schema.Route{...}).Handle(createHandler) // Schema 路由 — 附帶 metadata
核心型別
Route
type Route struct {
Method string // HTTP 方法(GET, POST, PUT, DELETE...)
Path string // 路由路徑(支援 :param 和 *catchall)
Summary string // 一行描述(給 AI 和文件用)
Description string // 詳細描述
Tags []string // 分類標籤
Input interface{} // 請求 body 的 Go struct(用於驗證)
Output interface{} // 回應 body 的 Go struct(用於驗證)
InputName string // 自動填入,無需手動設定
OutputName string // 自動填入,無需手動設定
Params []ParamSchema // 路徑/查詢參數描述
Headers []HeaderSchema // 必要標頭描述
Responses map[int]ResponseSchema // 各狀態碼的回應描述
}
ParamSchema
type ParamSchema struct {
Name string // 參數名稱
In string // "path", "query", "header"
Required bool // 是否必填
Type string // "string", "int", "bool"
Desc string // 描述
}
ResponseSchema
type ResponseSchema struct {
Description string // 回應描述
Type interface{} // Go struct type(用於 Contract Testing 驗證)
TypeName string // 自動填入
}
Registry(全域註冊表)
所有透過 Schema() 註冊的路由都會自動存入全域 Registry:
// 查詢特定路由的 schema
route, ok := schema.Global().Get("POST", "/api/users")
// 取得所有已註冊的 schema
all := schema.Global().All()
// 查看已註冊數量
count := schema.Global().Len()
// 清空(測試用)
schema.Global().Reset()
Registry 為 thread-safe,使用 sync.RWMutex 保護。
反射工具
提供型別內省工具,供 Manifest 和 Contract Testing 使用:
// 取得型別名稱
schema.TypeName(UserResponse{}) // → "UserResponse"
// 取得 struct 欄位資訊
fields := schema.FieldsOf(UserResponse{})
// → [{Name:"id", Type:"integer", Required:true}, ...]
// 驗證 JSON 是否符合 struct(含必填欄位檢查)
err := schema.ValidateJSON([]byte(`{"name":"alice"}`), CreateUserRequest{})
// 生成零值 JSON(用於自動測試)
data := schema.GenerateZeroJSON(CreateUserRequest{})
// → {"name":"","email":""}
Required 判定規則
| 條件 | Required |
|---|---|
Name string \json:"name"`` |
✅ 是 |
Email string \json:"email,omitempty"`` |
❌ 否(omitempty) |
Bio *string \json:"bio"`` |
❌ 否(pointer) |
json:"-" |
跳過(不出現) |
架構
pkg/schema/
├── schema.go Route、SchemaRoute、ParamSchema 等型別定義
├── registry.go 全域 thread-safe Registry
├── reflect.go TypeName、FieldsOf、ValidateJSON 反射工具
└── schema_test.go 18 個單元測試
依賴關係
pkg/schema ← 僅依賴 pkg/context(HandlerFunc 型別)
← 不依賴 pkg/router(避免迴圈依賴)
SchemaRegistrar 介面由 schema 定義,Router 和 Group 實作,避免迴圈依賴。
測試
go test ./pkg/schema/... -v
涵蓋:TypeName、FieldsOf、ValidateJSON、GenerateZeroJSON、Registry CRUD、SchemaRoute builder、goTypeToSchemaType。