-
Notifications
You must be signed in to change notification settings - Fork 0
router_en.md
The router package implements the core routing dispatch mechanism for HypGo. Built on an efficient Radix Tree implementation, it offers extremely fast route matching, supports dynamic parameter extraction and wildcard matching, and integrates route group management to greatly simplify API structure organization for large applications.
- Zero-Configuration High-Performance Radix Tree: Automatically builds a prefix tree for route lookups, far outperforming regular expression-based matching.
-
RESTful Parameters and Wildcards: Such as
:id(named match) and*filepath(wildcard match). - Built-in Memory Cache (LRU Route Cache): When enabled at startup, caches frequently accessed route resolution results, boosting high-concurrency route matching performance by another order of magnitude.
- Flexible Middleware and Groups: Manage routes with specific prefixes through route groups, and insert middleware at global or Group-specific levels.
-
Strict or Lenient Slash Handling (Strict Slash): Configurable whether
/pathand/path/are treated as the same path with automatic redirect. -
Seamless HTTP/3 Integration: Provides an
EnableHTTP3mechanism for native integration of HTTP/3 and QUIC into routing support.
Initialize a router and add simple paths:
package main import ( "github.com/maoxiaoyue/hypgo/pkg/context" "github.com/maoxiaoyue/hypgo/pkg/router" ) func main() { // Create router with default configuration r := router.New() // Basic GET / POST r.GET("/ping", func(c *context.Context) { c.String(200, "pong") }) r.POST("/submit", func(c *context.Context) { c.String(200, "Submitted!") }) // Start with HTTP Server in main (handled by pkg/server) }
Access path parameters defined by :name or *action:
// Matches /user/alice, /user/bob, etc. r.GET("/user/:name", func(c *context.Context) { name := c.Param("name") c.String(200, "Hello %s", name) }) // Matches /files/js/main.js or /files/css/style.css r.GET("/files/*filepath", func(c *context.Context) { path := c.Param("filepath") c.String(200, "Requested file path: %s", path) })
Route groups make it easy to separate different business logic:
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 Use to mount hypcontext.HandlerFunc at different levels:
// Global: all requests through this router pass through Middleware1, Middleware2 r.Use(Middleware1, Middleware2) // Group-specific: only mounted on the api group api := r.NewGroup("/api/v1") api.Use(AuthMiddleware) api.GET("/secure", secureHandler) // Must pass AuthMiddleware first
router.New also supports functional options for detailed configuration:
opts := []router.RouterOption{ router.WithCache(1000), // Enable LRU Route Cache, cache 1000 results router.WithStrictSlash(true), // Strictly differentiate trailing slash router.WithMethodNotAllowed(true), // Automatically catch and respond with 405 Method Not Allowed } r := router.New(opts...)
Beyond traditional route registration, Router supports the Schema() method, attaching metadata (input/output types, descriptions, tags) to routes for AI understanding of API behavior, Manifest generation, and Contract Testing:
import "github.com/maoxiaoyue/hypgo/pkg/schema" // Define route with metadata r.Schema(schema.Route{ Method: "POST", Path: "/api/users", Summary: "Create user", Tags: []string{"users"}, Input: CreateUserRequest{}, Output: UserResponse{}, Responses: map[int]schema.ResponseSchema{ 201: {Description: "User created"}, 400: {Description: "Invalid input"}, }, }).Handle(createUserHandler)
Groups also support Schema, automatically prepending the basePath prefix:
api := r.NewGroup("/api/v1") api.Schema(schema.Route{ Method: "GET", Path: "/products", Summary: "Get product list", }).Handle(listProductsHandler) // -> Automatically registered as GET /api/v1/products
Schema routes and traditional routes can coexist with full backward compatibility.
v0.8.5+Multi-protocol support is new in v0.8.5. v0.8.1 only supports REST.
The Router's Schema system is not limited to REST — it simultaneously supports gRPC, Bot, MCP, WebSocket, and CLI protocols. All protocols share a single Schema Registry, so the AI only needs to read one manifest to understand the entire application.
| Protocol | Command Format | Description |
|---|---|---|
rest |
Method + Path (auto) |
Traditional HTTP RESTful API |
grpc |
Service/Method |
gRPC remote call (Protobuf) |
bot |
/command or event name |
Chatbots (Telegram, Line, Discord, etc.) |
mcp |
tool_name |
Model Context Protocol tools |
websocket |
message_type |
Bidirectional WebSocket messages |
cli |
command_name |
CLI subcommands |
import ( "github.com/maoxiaoyue/hypgo/pkg/schema" hypgrpc "github.com/maoxiaoyue/hypgo/pkg/grpc" ) // Register gRPC schema (command format: Service/Method) schema.RegisterGRPC("UserService/CreateUser", "Create user", CreateUserReq{}, UserResp{}) schema.RegisterGRPC("UserService/GetUser", "Get user info", GetUserReq{}, UserResp{}) schema.RegisterGRPC("UserService/ListUsers", "List all users", ListUsersReq{}, ListUsersResp{}) // Start gRPC Server grpcServer := hypgrpc.New(hypgrpc.Config{ Addr: ":9090", EnableReflection: true, EnableHealthCheck: true, TLS: &hypgrpc.TLSConfig{ CertFile: "cert.pem", KeyFile: "key.pem", }, }, logger) pb.RegisterUserServiceServer(grpcServer.GRPCServer(), &userService{}) go grpcServer.Start() defer grpcServer.GracefulStop()
// Cross-platform commands schema.RegisterBot("/start", "Start the bot", nil, WelcomeMsg{}) schema.RegisterBot("/help", "Show help", nil, HelpMsg{}) // Telegram-specific schema.RegisterBotPlatform("telegram", "/game", "Start game", GameOpts{}, GameState{}) // Discord-specific (using ! prefix) schema.RegisterBotPlatform("discord", "!play", "Play music", PlayReq{}, PlayResp{}) // LINE event schema.RegisterBotPlatform("line", "follow", "User follow event", nil, FollowResp{})
schema.RegisterMCP("search_repos", "Search GitHub repositories", SearchInput{}, SearchOutput{}) schema.RegisterMCP("create_issue", "Create an Issue", CreateIssueReq{}, IssueResp{}) schema.RegisterMCP("run_query", "Execute database query", QueryInput{}, QueryResult{})
schema.RegisterWebSocket("join_room", "Join room", JoinReq{}, JoinResp{}) schema.RegisterWebSocket("send_message", "Send message", SendMsgReq{}, SendMsgResp{}) schema.RegisterWebSocket("leave_room", "Leave room", LeaveReq{}, nil) schema.RegisterWebSocket("sync_state", "Sync game state", nil, GameState{})
schema.RegisterCLI("process", "Process data files", ProcessFlags{}, ProcessResult{}) schema.RegisterCLI("export", "Export report", ExportFlags{}, ExportResult{})
// Filter by protocol grpcRoutes := schema.Global().GetByProtocol("grpc") botRoutes := schema.Global().GetByProtocol("bot") wsRoutes := schema.Global().GetByProtocol("websocket") // Query by full 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 backward-compatible query route, ok = schema.Global().Get("POST", "/api/users") // Get all (all protocols) all := schema.Global().All()
A common scenario — exposing REST externally (for frontend/third parties) and gRPC internally (for microservices):
func main() { r := router.New() log := logger.NewLogger() // REST API (external) api := r.NewGroup("/api/v1") api.Schema(schema.Route{ Method: "POST", Path: "/orders", Summary: "Create order", 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 (internal microservice communication) schema.RegisterGRPC("OrderService/CreateOrder", "Create order (internal)", InternalOrderReq{}, OrderResp{}) schema.RegisterGRPC("InventoryService/CheckStock", "Check inventory", CheckStockReq{}, StockResp{}) // Start REST server (HTTP/2 + TLS) srv := server.New(cfg, r) go srv.Start() // Start gRPC server grpcSrv := hypgrpc.New(hypgrpc.Config{ Addr: ":9090", EnableReflection: true, EnableHealthCheck: true, }, log) pb.RegisterOrderServiceServer(grpcSrv.GRPCServer(), &orderService{}) grpcSrv.Start() }
Get all registered route information (including handler function names) via Routes():
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 are obtained via runtime.FuncForPC reflection, used by Manifest and debugging.
If a route only has a GET handler registered, HEAD requests automatically use the GET handler (no need for duplicate registration):
r.GET("/api/status", statusHandler) // HEAD /api/status -> Automatically uses statusHandler (response without body)
When WithStrictSlash(true) is enabled, /path and /path/ are automatically redirected (HTTP 301):
r := router.New(router.WithStrictSlash(true)) r.GET("/users", listUsers) // GET /users/ -> 301 redirect to /users // GET /users -> Normal response
Router has two GC optimizations on the hot path for high concurrency:
makeContextParams() uses hypcontext.AcquireParams() to get Params slices from a pool, avoiding per-request make(Params, n) allocations. Route parameters are returned to the pool when the request ends.
LRU cache cacheItem objects are managed via sync.Pool. New cache items are taken from the pool, and evicted items are cleared and returned, eliminating frequent &cacheItem{} allocations.
設計文件
套件
- 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