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

router_en.md

maoxiaoyue edited this page May 14, 2026 · 1 revision

Router Package (pkg/router)

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.

Key Features

  • 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 /path and /path/ are treated as the same path with automatic redirect.
  • Seamless HTTP/3 Integration: Provides an EnableHTTP3 mechanism for native integration of HTTP/3 and QUIC into routing support.

Basic Usage

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

Route Parameter Matching

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

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

Global and Group Middleware

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

Custom Configuration

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

Schema-first Routes (AI Collaboration)

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.

Multi-Protocol Schema Registration

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.

Supported Protocols

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

gRPC Example

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

Bot Example (Multi-Platform Chatbot)

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

MCP Example (Model Context Protocol)

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

WebSocket Example

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

CLI Example

schema.RegisterCLI("process", "Process data files", ProcessFlags{}, ProcessResult{})
schema.RegisterCLI("export", "Export report", ExportFlags{}, ExportResult{})

Querying Registered Multi-Protocol Schemas

// 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()

REST + gRPC Dual-Protocol Server Example

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

Route Information Query

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.

Automatic HEAD Response

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)

Trailing Slash Redirect

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

GC Optimizations

Router has two GC optimizations on the hot path for high concurrency:

Params Pool

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.

RouteCache cacheItem Pool

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.

HypGo

繁體中文 | English


中文文件

設計文件

套件

AI 協作工具鏈

CLI 命令


English Docs

Design Docs

Packages

AI Collaboration Toolchain

CLI Commands

Clone this wiki locally

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