-
Notifications
You must be signed in to change notification settings - Fork 0
router.md
router 套件為 HypGo 實現了核心的路由分發機制。它基於高效的基數樹(Radix Tree)實作,擁有極快的路由比對速度,支援動態參數擷取與萬用字元配對,同時將路由群組管理整合在內,大幅簡化大型應用的 API 結構組織。
- 零配置的高效能 Radix Tree: 自動化建立前綴樹進行路由檢索,執行速度遠勝一般基於 Regular Expression 的配對方式。
-
支援 RESTful 參數與萬用字元: 如
:id(名稱配對)、*filepath(萬用配對)。 - 內建記憶體快取 (LRU Route Cache): 若啟動時啟用,可以快取頻繁造訪的路由解析結果,使極高併發的路由比對效能再提升一個量級。
- 靈活的中間件與群組 (Group): 透過路由群組管理特定前綴的路由,並且能夠為全域或是特定的 Group 插入中介軟體(Middleware)。
-
嚴格或寬鬆的斜線處理 (Strict Slash): 可配置是否將
/path與/path/視作同一路徑並自動重新導向。 -
無縫整合 HTTP/3: 提供
EnableHTTP3機制讓 HTTP/3 與 QUIC 原生整合進路由的支援中。
初始化一個路由器並加入簡單的路徑:
package main import ( "github.com/maoxiaoyue/hypgo/pkg/context" "github.com/maoxiaoyue/hypgo/pkg/router" ) func main() { // 使用預設配置建立路由器 r := router.New() // 基礎的 GET / POST r.GET("/ping", func(c *context.Context) { c.String(200, "pong") }) r.POST("/submit", func(c *context.Context) { c.String(200, "Submitted!") }) // 在 main 裡面搭配 Http Server 啟動 (由 pkg/server 負責) }
存取由 :name 或 *action 定義的路徑參數:
// 匹配 /user/alice, /user/bob 等 r.GET("/user/:name", func(c *context.Context) { name := c.Param("name") c.String(200, "Hello %s", name) }) // 匹配 /files/js/main.js 或 /files/css/style.css r.GET("/files/*filepath", func(c *context.Context) { path := c.Param("filepath") c.String(200, "Requested file path: %s", path) })
透過路由群組,能很方便的將不同業務邏輯切割開來:
api := r.NewGroup("/api/v1") { users := api.NewGroup("/users") { users.GET("/", listUsers) // /api/v1/users/ users.GET("/:id", getUser) // /api/v1/users/:id users.POST("/", createUser) // /api/v1/users/ } orders := api.NewGroup("/orders") { orders.GET("/", listOrders) // /api/v1/orders/ orders.GET("/:id", getOrder) // /api/v1/orders/:id } }
使用 Use 可以在不同層級掛載 hypcontext.HandlerFunc:
// 全域套用:所有經過此路由器的請求都會先經過 Middleware1, Middleware2 r.Use(Middleware1, Middleware2) // 單獨掛載:僅掛載於 api 群組 api := r.NewGroup("/api/v1") api.Use(AuthMiddleware) api.GET("/secure", secureHandler) // 必須經過 AuthMiddleware 才會執行
router.New 也開放以函數式選項進行詳細設定:
opts := []router.RouterOption{ router.WithCache(1000), // 啟用 LRU Route Cache,快取 1000 條結果 router.WithStrictSlash(true), // 嚴格區分結尾斜線 router.WithMethodNotAllowed(true), // 自動捕捉並回應 405 Method Not Allowed } r := router.New(opts...)
除了傳統的路由註冊,Router 支援 Schema() 方法,讓路由攜帶 metadata(輸入/輸出型別、描述、標籤),供 AI 理解 API 行為、Manifest 生成與 Contract Testing 使用:
import "github.com/maoxiaoyue/hypgo/pkg/schema" // 定義帶 metadata 的路由 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)
Group 也支援 Schema,會自動加上 basePath 前綴:
api := r.NewGroup("/api/v1") api.Schema(schema.Route{ Method: "GET", Path: "/products", Summary: "取得商品列表", }).Handle(listProductsHandler) // → 自動註冊為 GET /api/v1/products
Schema 路由與傳統路由可並存,完全向後相容。
v0.8.5+多協議支援為 v0.8.5 新增功能。v0.8.1 僅支援 REST 協議。
Router 的 Schema 系統不僅限於 REST,同時支援 gRPC、Bot、MCP、WebSocket、CLI 六種協議。所有協議共用同一個 Schema Registry,AI 只需讀一份 manifest 就能理解整個應用的所有 API。
| 協議 | Command 格式 | 說明 |
|---|---|---|
rest |
Method + Path(自動) |
傳統 HTTP RESTful API |
grpc |
Service/Method |
gRPC 遠端呼叫(Protobuf) |
bot |
/command 或事件名 |
聊天機器人(Telegram、Line、Discord 等) |
mcp |
tool_name |
Model Context Protocol 工具 |
websocket |
message_type |
WebSocket 雙向訊息 |
cli |
command_name |
CLI 子命令 |
gRPC 方法透過 schema.RegisterGRPC() 註冊到全域 Registry,與 pkg/grpc Server 搭配使用:
import ( "github.com/maoxiaoyue/hypgo/pkg/schema" hypgrpc "github.com/maoxiaoyue/hypgo/pkg/grpc" ) // 定義 gRPC 請求/回應型別 type CreateUserReq struct { Name string `json:"name"` Email string `json:"email"` } type UserResp struct { ID int `json:"id"` Name string `json:"name"` Email string `json:"email"` } // 註冊 gRPC schema(Command 格式:Service/Method) schema.RegisterGRPC("UserService/CreateUser", "建立使用者", CreateUserReq{}, UserResp{}) schema.RegisterGRPC("UserService/GetUser", "取得使用者資訊", GetUserReq{}, UserResp{}) schema.RegisterGRPC("UserService/ListUsers", "列出所有使用者", ListUsersReq{}, ListUsersResp{}) // 啟動 gRPC Server grpcServer := hypgrpc.New(hypgrpc.Config{ Addr: ":9090", EnableReflection: true, EnableHealthCheck: true, TLS: &hypgrpc.TLSConfig{ CertFile: "cert.pem", KeyFile: "key.pem", }, }, logger) // 註冊 gRPC 服務實作(標準 protobuf 服務) pb.RegisterUserServiceServer(grpcServer.GRPCServer(), &userService{}) // 啟動 go grpcServer.Start() defer grpcServer.GracefulStop()
gRPC Schema 在 Registry 中的查詢 key 為 grpc|UserService/CreateUser,可透過 schema.Global().GetByKey() 查詢,或用 schema.Global().GetByProtocol("grpc") 取得所有 gRPC 路由。
Bot schema 支援跨平台或平台專屬兩種模式:
// 跨平台通用指令 schema.RegisterBot("/start", "啟動機器人", nil, WelcomeMsg{}) schema.RegisterBot("/help", "顯示幫助", nil, HelpMsg{}) // Telegram 專屬指令 schema.RegisterBotPlatform("telegram", "/game", "開始遊戲", GameOpts{}, GameState{}) schema.RegisterBotPlatform("telegram", "/settings", "用戶設定", nil, SettingsResp{}) // Discord 專屬指令(使用 ! 前綴) schema.RegisterBotPlatform("discord", "!play", "播放音樂", PlayReq{}, PlayResp{}) schema.RegisterBotPlatform("discord", "!queue", "顯示播放佇列", nil, QueueResp{}) // LINE 專屬事件 schema.RegisterBotPlatform("line", "follow", "用戶追蹤事件", nil, FollowResp{})
跨平台指令的 key 為 bot|/start,平台專屬指令會自動加入平台 tag 供篩選。
MCP 用於定義 AI 工具呼叫的合約:
// MCP tool 註冊 schema.RegisterMCP("search_repos", "搜尋 GitHub 倉庫", SearchInput{}, SearchOutput{}) schema.RegisterMCP("create_issue", "建立 Issue", CreateIssueReq{}, IssueResp{}) schema.RegisterMCP("run_query", "執行資料庫查詢", QueryInput{}, QueryResult{})
WebSocket 訊息類型透過 RegisterWebSocket 定義雙向通訊合約:
// WebSocket 訊息類型 schema.RegisterWebSocket("join_room", "加入房間", JoinReq{}, JoinResp{}) schema.RegisterWebSocket("send_message", "發送訊息", SendMsgReq{}, SendMsgResp{}) schema.RegisterWebSocket("leave_room", "離開房間", LeaveReq{}, nil) schema.RegisterWebSocket("sync_state", "同步遊戲狀態", nil, GameState{})
CLI 子命令的 schema 讓 AI 能理解命令列工具的輸入輸出:
// CLI 子命令 schema.RegisterCLI("process", "處理資料檔案", ProcessFlags{}, ProcessResult{}) schema.RegisterCLI("export", "匯出報表", ExportFlags{}, ExportResult{})
// 按協議篩選 grpcRoutes := schema.Global().GetByProtocol("grpc") botRoutes := schema.Global().GetByProtocol("bot") wsRoutes := schema.Global().GetByProtocol("websocket") // 用完整 key 查詢 route, ok := schema.Global().GetByKey("grpc|UserService/CreateUser") route, ok = schema.Global().GetByKey("bot|/start") route, ok = schema.Global().GetByKey("mcp|search_repos") route, ok = schema.Global().GetByKey("websocket|join_room") // REST 向後相容查詢 route, ok = schema.Global().Get("POST", "/api/users") // 取得全部(所有協議) all := schema.Global().All()
一個同時提供 REST、gRPC、WebSocket、Bot 的完整應用:
func main() { r := router.New() // ── REST API ── r.Schema(schema.Route{ Method: "POST", Path: "/api/users", Summary: "建立使用者", Tags: []string{"users"}, Input: CreateUserReq{}, Output: UserResp{}, }).Handle(createUserHandler) r.Schema(schema.Route{ Method: "GET", Path: "/api/users/:id", Summary: "取得使用者", Tags: []string{"users"}, Output: UserResp{}, }).Handle(getUserHandler) // ── gRPC ── schema.RegisterGRPC("UserService/CreateUser", "建立使用者", CreateUserReq{}, UserResp{}) schema.RegisterGRPC("UserService/GetUser", "取得使用者", GetUserReq{}, UserResp{}) // ── WebSocket ── schema.RegisterWebSocket("join_room", "加入房間", JoinReq{}, JoinResp{}) schema.RegisterWebSocket("chat", "聊天訊息", ChatMsg{}, ChatMsg{}) // ── Bot ── schema.RegisterBot("/start", "啟動機器人", nil, WelcomeMsg{}) schema.RegisterBotPlatform("telegram", "/game", "開始遊戲", GameOpts{}, GameState{}) // 產出的 Manifest 會包含以上所有協議的 API 描述 // AI 讀一個 manifest 就能理解整個應用 srv := server.New(cfg, r) srv.Start() }
常見場景:同一服務同時對外提供 REST API(給前端/第三方),對內提供 gRPC(給微服務):
func main() { r := router.New() log := logger.NewLogger() // REST API(對外) api := r.NewGroup("/api/v1") api.Schema(schema.Route{ Method: "GET", Path: "/products", Summary: "取得商品列表", Tags: []string{"products"}, Output: []ProductResp{}, }).Handle(listProducts) api.Schema(schema.Route{ Method: "POST", Path: "/orders", Summary: "建立訂單", Tags: []string{"orders"}, Input: CreateOrderReq{}, Output: OrderResp{}, Responses: map[int]schema.ResponseSchema{ 201: {Description: "Order created"}, 400: {Description: "Invalid input"}, 409: {Description: "Insufficient stock"}, }, }).Handle(createOrder) // gRPC(對內微服務間通訊) schema.RegisterGRPC("OrderService/CreateOrder", "建立訂單(內部)", InternalOrderReq{}, OrderResp{}) schema.RegisterGRPC("OrderService/UpdateStock", "更新庫存", UpdateStockReq{}, StockResp{}) schema.RegisterGRPC("InventoryService/CheckStock", "庫存查詢", CheckStockReq{}, StockResp{}) // 啟動 REST Server(HTTP/2 + TLS) srv := server.New(cfg, r) go srv.Start() // 啟動 gRPC Server grpcSrv := hypgrpc.New(hypgrpc.Config{ Addr: ":9090", EnableReflection: true, EnableHealthCheck: true, }, log) pb.RegisterOrderServiceServer(grpcSrv.GRPCServer(), &orderService{}) pb.RegisterInventoryServiceServer(grpcSrv.GRPCServer(), &inventoryService{}) grpcSrv.Start() }
透過 Routes() 取得所有已註冊的路由資訊(含 handler 函式名稱):
for _, route := range r.Routes() { fmt.Printf("%s %s → %v\n", route.Method, route.Path, route.HandlerNames) } // GET /health → [main.healthHandler] // POST /api/users → [controllers.CreateUser]
HandlerNames 透過 runtime.FuncForPC 反射取得,供 Manifest 和偵錯使用。
若路由只註冊了 GET handler,HEAD 請求會自動使用 GET handler 回應(不需重複註冊):
r.GET("/api/status", statusHandler) // HEAD /api/status → 自動使用 statusHandler(回應不含 body)
啟用 WithStrictSlash(true) 時,自動將 /path ↔ /path/ 重導向(HTTP 301):
r := router.New(router.WithStrictSlash(true)) r.GET("/users", listUsers) // GET /users/ → 301 重導向到 /users // GET /users → 正常回應
Router 在高併發路徑上做了兩項 GC 優化:
makeContextParams() 使用 hypcontext.AcquireParams() 從 pool 取得 Params slice,避免每請求 make(Params, n) 分配。路由參數在請求結束後歸還 pool。
LRU 快取的 cacheItem 使用 sync.Pool 管理。新增快取項目時從 pool 取得,淘汰時清空欄位後歸還,消除頻繁的 &cacheItem{} 分配。
設計文件
套件
- 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