Ming Router now supports advanced routing with named parameters, optional parameters, regex validation, and catch-all parameters.
Named parameters are defined using curly braces {name} and match a single path segment.
r.Get("/user/{name}", func(ctx *fasthttp.RequestCtx) {
name := ming.Param(ctx, "name")
fmt.Fprintf(ctx, "Hello, %s!", name)
})Examples:
/user/john✅ matches/user/jane✅ matches/user/john/profile❌ no match (contains additional segment)/user/❌ no match (empty parameter)
Optional parameters are defined by adding ? after the parameter name: {name?}
r.Get("/api/users/{id?}", func(ctx *fasthttp.RequestCtx) {
id := ming.Param(ctx, "id")
if id == "" {
ctx.WriteString("List all users")
} else {
fmt.Fprintf(ctx, "Get user: %s", id)
}
})Examples:
/api/users/✅ matches (id is empty)/api/users/123✅ matches (id is "123")
Parameters can include regex validation using the syntax {name:[regex]}:
// Only numeric IDs
r.Get("/product/{id:[0-9]+}", func(ctx *fasthttp.RequestCtx) {
id := ming.Param(ctx, "id")
fmt.Fprintf(ctx, "Product ID: %s", id)
})
// Only alphabetic names
r.Get("/category/{name:[a-zA-Z]+}", func(ctx *fasthttp.RequestCtx) {
name := ming.Param(ctx, "name")
fmt.Fprintf(ctx, "Category: %s", name)
})Examples:
/product/123✅ matches/product/abc❌ no match (not numeric)/category/electronics✅ matches/category/123❌ no match (not alphabetic)
Combine optional parameters with regex validation: {name?:[regex]}
r.Get("/article/{slug?:[a-z0-9-]+}", func(ctx *fasthttp.RequestCtx) {
slug := ming.Param(ctx, "slug")
if slug == "" {
ctx.WriteString("List all articles")
} else {
fmt.Fprintf(ctx, "Article: %s", slug)
}
})Catch-all parameters use {name:*} and match everything including slashes. They must be at the end of the path.
r.Get("/files/{filepath:*}", func(ctx *fasthttp.RequestCtx) {
filepath := ming.Param(ctx, "filepath")
fmt.Fprintf(ctx, "File: %s", filepath)
})Examples:
/files/✅ matches (filepath is empty)/files/readme.txt✅ matches/files/docs/readme.txt✅ matches/files/path/to/deep/file.pdf✅ matches
Ming supports registering multiple catch-all routes with different prefixes in the same router instance. This is useful for creating file servers, API proxies, or any application that needs to handle different types of wildcard paths.
// These will work together - multiple catch-all routes with different prefixes
r.Get("/files/{filepath:*}", filesHandler)
r.Get("/documents/{docpath:*}", docsHandler)
r.Get("/api/v1/proxy/{url:*}", proxyHandler)
r.Get("/media/{mediapath:*}", mediaHandler)
// This will cause a panic - same prefix with different catch-all parameter name
r.Get("/files/{otherpath:*}", otherHandler)Examples with multiple catch-all routes:
/files/report.pdf✅ matches filesHandler/documents/contract.docx✅ matches docsHandler/api/v1/proxy/https://example.com✅ matches proxyHandler/media/videos/demo.mp4✅ matches mediaHandler
URL Handling Note: When using catch-all routes with URLs (like in a proxy), be aware that URLs containing http:// or https:// will have one slash removed in the captured parameter. For example, /api/v1/proxy/https://example.com will capture https:/example.com (with one slash removed). Your handler should account for this when processing URLs.
See the multiple catch-all example for a complete implementation.
Parameters can have suffixes:
r.Get("/admin/{name}_profile", func(ctx *fasthttp.RequestCtx) {
name := ming.Param(ctx, "name")
fmt.Fprintf(ctx, "Admin profile: %s", name)
})Examples:
/admin/john_profile✅ matches/admin/jane_profile✅ matches/admin/john❌ no match (missing suffix)
// Get parameter value as string
name := ming.Param(ctx, "paramName")
// Get raw user value (returns interface{})
value := ming.UserValue(ctx, "paramName")r.Get("/api/{version:[v][0-9]+}/users/{userId:[0-9]+}/files/{filepath:*}",
func(ctx *fasthttp.RequestCtx) {
version := ming.Param(ctx, "version")
userId := ming.Param(ctx, "userId")
filepath := ming.Param(ctx, "filepath")
fmt.Fprintf(ctx, "API %s, User %s, File %s",
version, userId, filepath)
})This matches: /api/v1/users/123/files/documents/report.pdf
The router uses a radix tree with priority-based matching:
- Static routes have highest priority
- Routes with parameters are evaluated by registration order
- Catch-all routes have lowest priority
- Invalid regex patterns will panic during route registration
- Catch-all parameters not at the end will panic
- Parameters that don't match their regex validation will not match the route