Documentation
¶
Overview ¶
Package match provides a small generic path router.
A Router maps path patterns to caller-provided values and matches paths against those patterns. The zero value is ready to use, and the stored value can be any Go type.
Route Grammar ¶
Routes are slash-separated patterns made from literal text, named parameters, and catch-all parameters. A route does not have to start with /, but it is matched exactly as registered; match does not clean paths, decode escapes, or add a leading slash.
Literal text matches itself. A named parameter is written as {name} and captures one non-empty path segment. A parameter may have literal text before or after it in the same segment, such as /files/{name}.json or /user_{id}. Each path segment may contain at most one parameter.
A catch-all parameter is written as {*name}. It captures the non-empty remainder of the path, including any slashes, and must appear at the end of the route. A catch-all may have a literal prefix in its final segment, such as /static/prefix-{*path}; the captured value starts after that prefix.
Literal braces are escaped by doubling them: {{ matches a literal { and }} matches a literal }. Escaped braces may also appear inside parameter names.
Parameter names must be non-empty. Names cannot contain /, and * is only valid as the first character of a catch-all parameter. Parameters and catch-all parameters capture non-empty text.
Matching and Conflicts ¶
When more than one route could match, match chooses the most specific route: exact literal segments beat parameter segments, parameter segments with more literal text are tried first, and catch-all routes are considered last.
TryInsert returns an error for invalid, duplicate, or ambiguous routes. Invalid route syntax is reported with sentinel errors such as ErrInvalidParam, ErrInvalidParamSegment, and ErrInvalidCatchAll. Duplicate and ambiguous routes return *ConflictError. For example, /x/{id}/bar conflicts with /x/{name}/bar because both match the same set of paths. Insert panics on the same errors returned by TryInsert.
Matching returns parameters in route order. Params is an opaque value type; use Len and At to iterate without allocation, Get or TryGet to look up named parameters, Seq for range-over-function iteration, Merge to concatenate parameter sets, and AppendTo or All when a []Param snapshot is needed. Match stores up to four parameters inline and allocates only when more storage is needed, while MatchInto reuses the caller-provided Params value. MatchPrefix and MatchPrefixInto return the best whole-segment route prefix plus the remaining path, which is useful for mounts and nested dispatch.
After routes are registered, a Router may be used by multiple goroutines for matching. Callers that insert routes while other goroutines use the router must synchronize access.
Examples ¶
var router match.Router[string]
router.Insert("/posts/{year}/{slug}", "post")
router.Insert("/static/{*path}", "asset")
value, params, ok := router.Match("/posts/2026/route-grammar")
_ = value // "post"
_ = params.Get("year") // "2026"
_ = ok // true
Index ¶
- Variables
- type ConflictError
- type Param
- type Params
- type PrefixMatch
- type Router
- func (r *Router[T]) Insert(route string, value T)
- func (r *Router[T]) Match(path string) (T, Params, bool)
- func (r *Router[T]) MatchInto(path string, params Params) (T, Params, bool)
- func (r *Router[T]) MatchPrefix(path string) (PrefixMatch[T], bool)
- func (r *Router[T]) MatchPrefixInto(path string, params Params) (PrefixMatch[T], bool)
- func (r *Router[T]) TryInsert(route string, value T) error
Constants ¶
This section is empty.
Variables ¶
var ( // ErrInvalidParamSegment reports a route segment that contains more than // one parameter. ErrInvalidParamSegment = errors.New("only one parameter is allowed per path segment") // ErrInvalidParam reports malformed parameter syntax or an invalid // parameter name. ErrInvalidParam = errors.New("parameters must be registered with a valid name") // ErrInvalidCatchAll reports a catch-all parameter that is not the final // token in its route. ErrInvalidCatchAll = errors.New("catch-all parameters are only allowed at the end of a route") )
Functions ¶
This section is empty.
Types ¶
type ConflictError ¶
type ConflictError struct {
// Route is the route that failed to insert.
Route string
// With is the previously registered route that conflicts with Route.
With string
}
ConflictError reports a route that cannot be inserted because it overlaps an already registered route.
func (*ConflictError) Error ¶
func (e *ConflictError) Error() string
Error returns a human-readable description of the route conflict.
type Param ¶
type Param struct {
// Key is the parameter name from the matched route.
Key string
// Val is the substring captured from the matched path.
Val string
}
Param is one captured route parameter.
type Params ¶
type Params struct {
// contains filtered or unexported fields
}
Params stores captured route parameters in route order.
Params is an opaque value type. Use Len and At to inspect captures without allocation, Get or TryGet to look up a named capture, and AppendTo or All when a []Param snapshot is needed. Up to four captures are stored inline.
func Merge ¶
Merge returns a Params value containing a followed by b.
Parameter keys are not deduplicated; when the same key appears in both inputs, the returned Params contains both captures in order.
func NewParams ¶
NewParams returns an empty Params value with room for capacity parameters.
It is most useful with Router.MatchInto when callers want to reuse storage across matches. Capacity values of four or less use the inline storage built into Params.
func (Params) AppendTo ¶
AppendTo appends the captured parameters to dst and returns the extended slice.
func (Params) At ¶
At returns the parameter at index i.
It panics if i is outside the range [0, Len()).
type PrefixMatch ¶
PrefixMatch contains the result of a successful prefix match.
Rest is the remaining path after the matched prefix. It is always "/" when the match consumes the full path.
type Router ¶
type Router[T any] struct { // contains filtered or unexported fields }
Router maps path patterns to caller-provided values.
The zero value is ready to use. After routes are registered, a Router may be used by multiple goroutines for matching. Callers that insert routes while other goroutines use the router must synchronize access.
func (*Router[T]) Insert ¶
Insert registers route with value.
It panics with the same errors returned by TryInsert when route is invalid or conflicts with an existing route.
func (*Router[T]) Match ¶
Match returns the value and parameters for path.
The boolean result is false when no registered route matches; in that case the value is the zero value of T and the returned Params is empty.
func (*Router[T]) MatchInto ¶
MatchInto returns the value and parameters for path using params as storage.
The input Params value is reset before matching. Use NewParams to create a reusable Params buffer large enough for the expected number of captures.
func (*Router[T]) MatchPrefix ¶
func (r *Router[T]) MatchPrefix(path string) (PrefixMatch[T], bool)
MatchPrefix returns the value, parameters, and remaining path for the best registered route that matches the front of path.
The boolean result is false when no registered route matches a whole-segment prefix of path. When multiple routes match, the route that consumes the most path wins. A route registered as "/" matches the root prefix of any absolute path.
func (*Router[T]) MatchPrefixInto ¶
func (r *Router[T]) MatchPrefixInto(path string, params Params) (PrefixMatch[T], bool)
MatchPrefixInto is like MatchPrefix, but uses params as parameter storage.
The input Params value is reset before matching. Use NewParams to create a reusable Params buffer large enough for the expected number of captures.