nestedmux

package
v0.85.0-pre.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 3, 2026 License: BSD-3-Clause Imports: 13 Imported by: 0

README

kit/nestedmux

github.com/vormadev/vorma/kit/nestedmux

Nested router that builds on kit/nestedmatcher and runs matched task handlers.

Use this package when a single request path should resolve to multiple nested patterns and optionally execute handlers for each matched pattern.

Import

import "github.com/vormadev/vorma/kit/nestedmux"

Quick Start

router := nestedmux.NewRouter(nil)

nestedmux.AddPatternWithoutHandler(router, "")
nestedmux.AddTaskHandler(
	router,
	"/users/:id",
	mux.TaskHandlerFromFunc(func(rd *mux.ReqData[mux.None]) (string, error) {
		return rd.Param("id"), nil
	}),
)

req := httptest.NewRequest(http.MethodGet, "/users/42", nil)
req = mux.RequestWithTasksCtx(req, tasks.NewCtx(context.Background()))

results, ok := nestedmux.FindMatchesAndRunTasks(router, req)
if ok {
	_ = results.Map["/users/:id"].Data() // "42"
}

Router Options

Defaults:

  • DynamicParamPrefix: ':'
  • SplatSegmentIdentifier: '*'
  • ExplicitIndexSegmentIdentifier: "" (disabled)

Core Behavior

  • FindMatches returns nested matcher results for r.URL.Path.
  • FindMatchesAndRunTasks runs task handlers for matched patterns.
  • TasksResults.Slice preserves match order.
  • TasksResults.Map gives direct lookup by pattern.
  • TasksResult.RanTask() is false for matched patterns without handlers.

Task Execution Notes

  • Requests must carry a tasks.Ctx (mux.RequestWithTasksCtx is the helper).
  • RunTasks runs matched tasks in parallel.
  • On task error, descendant task contexts are canceled while already-running sibling tasks can still complete.
  • Task results always include per-pattern response proxies for downstream merge.

Lifecycle And Concurrency Notes

  • Register routes before serving traffic.
  • AllRoutes and Matcher return defensive copies.
  • AddPatternWithoutHandlerIfMissing is safe to call concurrently for the same router instance.
  • ReplaceRoutes and RebuildPreservingHandlers support atomic route table replacement for dynamic rebuild flows.

Public API

Types
  • type ReqData
  • type Options
  • type Router
  • type Route[O any]
  • type AnyRoute
  • type TasksResult
  • type TasksResults
Functions
  • func NewRouter(opts *Options) *Router
  • func AddTaskHandler[O any](router *Router, pattern string, taskHandler *mux.TaskHandler[mux.None, O]) *Route[O]
  • func AddPatternWithoutHandler(router *Router, pattern string)
  • func FindMatches(nestedRouter *Router, r *http.Request) (*nestedmatcher.Results, bool)
  • func FindMatchesAndRunTasks(nestedRouter *Router, r *http.Request) (*TasksResults, bool)
  • func RunTasks(nestedRouter *Router, r *http.Request, findNestedMatchesResults *nestedmatcher.Results) *TasksResults
Router methods
  • func (nr *Router) AllRoutes() map[string]AnyRoute
  • func (nr *Router) IsRegistered(originalPattern string) bool
  • func (nr *Router) HasTaskHandler(originalPattern string) bool
  • func (nr *Router) ExplicitIndexSegmentIdentifier() string
  • func (nr *Router) DynamicParamPrefix() rune
  • func (nr *Router) SplatSegmentIdentifier() rune
  • func (nr *Router) Matcher() *nestedmatcher.Matcher
  • func (nr *Router) AddPatternWithoutHandlerIfMissing(pattern string) bool
  • func (nr *Router) ReplaceRoutes(newRoutes map[string]AnyRoute)
  • func (nr *Router) RebuildPreservingHandlers(patterns []string)
Route methods
  • func (route *Route[O]) OriginalPattern() string
TasksResult methods
  • func (ntr *TasksResult) Pattern() string
  • func (ntr *TasksResult) OK() bool
  • func (ntr *TasksResult) Data() any
  • func (ntr *TasksResult) Err() error
  • func (ntr *TasksResult) RanTask() bool
TasksResults methods
  • func (ntr *TasksResults) HasTaskHandlerAt(i int) bool

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddPatternWithoutHandler

func AddPatternWithoutHandler(router *Router, pattern string)

AddPatternWithoutHandler registers a nested pattern with no task handler.

func FindMatches

func FindMatches(
	nestedRouter *Router,
	r *http.Request,
) (*nestedmatcher.Results, bool)

FindMatches resolves nested route matches for the request path.

Types

type AnyRoute

type AnyRoute interface {
	OriginalPattern() string
	genericsutil.AnyZeroHelper
	// contains filtered or unexported methods
}

AnyRoute is the internal polymorphic route contract for Router.

type Options

type Options struct {
	DynamicParamPrefix             rune
	SplatSegmentIdentifier         rune
	ExplicitIndexSegmentIdentifier string
}

Options configures pattern matching behavior for Router.

type ReqData

type ReqData = mux.ReqData[mux.None]

type Route

type Route[O any] struct {
	genericsutil.ZeroHelper[mux.None, O]
	// contains filtered or unexported fields
}

Route stores metadata and optional task handler for one nested pattern.

func AddTaskHandler

func AddTaskHandler[O any](
	router *Router,
	pattern string,
	taskHandler *mux.TaskHandler[mux.None, O],
) *Route[O]

AddTaskHandler registers a nested pattern with a task handler.

func (*Route[O]) OriginalPattern

func (route *Route[O]) OriginalPattern() string

OriginalPattern returns the pattern as registered.

type Router

type Router struct {
	// contains filtered or unexported fields
}

Router stores nested route patterns and optional task handlers.

func NewRouter

func NewRouter(opts *Options) *Router

NewRouter creates a nested router with the provided options.

func (*Router) AddPatternWithoutHandlerIfMissing

func (nr *Router) AddPatternWithoutHandlerIfMissing(
	pattern string,
) bool

AddPatternWithoutHandlerIfMissing registers a pattern without a task handler only when it is not already present. It returns true if a new route was registered.

func (*Router) AllRoutes

func (nr *Router) AllRoutes() map[string]AnyRoute

AllRoutes returns a snapshot copy of registered nested routes.

func (*Router) DynamicParamPrefix

func (nr *Router) DynamicParamPrefix() rune

DynamicParamPrefix returns the dynamic param prefix rune.

func (*Router) ExplicitIndexSegmentIdentifier

func (nr *Router) ExplicitIndexSegmentIdentifier() string

ExplicitIndexSegmentIdentifier returns the explicit index marker string.

func (*Router) HasTaskHandler

func (nr *Router) HasTaskHandler(originalPattern string) bool

HasTaskHandler reports whether a pattern is registered with a handler.

func (*Router) IsRegistered

func (nr *Router) IsRegistered(originalPattern string) bool

IsRegistered reports whether a pattern is registered.

func (*Router) Matcher

func (nr *Router) Matcher() *nestedmatcher.Matcher

Matcher returns a copy of the nested matcher state.

func (*Router) RebuildPreservingHandlers

func (nr *Router) RebuildPreservingHandlers(patterns []string)

RebuildPreservingHandlers atomically rebuilds the router, preserving routes that have task handlers and replacing handler-less routes with the provided patterns. This is intended for dev-time fast rebuilds when only pattern definitions change.

func (*Router) ReplaceRoutes

func (nr *Router) ReplaceRoutes(newRoutes map[string]AnyRoute)

ReplaceRoutes atomically replaces all routes with a new set. This rebuilds the matcher from scratch, which is safe and fast for dev mode.

func (*Router) SplatSegmentIdentifier

func (nr *Router) SplatSegmentIdentifier() rune

SplatSegmentIdentifier returns the splat segment identifier rune.

type TasksResult

type TasksResult struct {
	// contains filtered or unexported fields
}

TasksResult stores task execution output for one matched pattern.

func (*TasksResult) Data

func (ntr *TasksResult) Data() any

Data returns task output data.

func (*TasksResult) Err

func (ntr *TasksResult) Err() error

Err returns task execution error.

func (*TasksResult) OK

func (ntr *TasksResult) OK() bool

OK reports whether task execution succeeded.

func (*TasksResult) Pattern

func (ntr *TasksResult) Pattern() string

Pattern returns the matched route pattern.

func (*TasksResult) RanTask

func (ntr *TasksResult) RanTask() bool

RanTask reports whether this match had a task handler.

type TasksResults

type TasksResults struct {
	Params          mux.Params
	SplatValues     []string
	Map             map[string]*TasksResult
	Slice           []*TasksResult
	ResponseProxies []*response.Proxy
}

TasksResults contains ordered and keyed task results for nested matches.

func FindMatchesAndRunTasks

func FindMatchesAndRunTasks(
	nestedRouter *Router,
	r *http.Request,
) (*TasksResults, bool)

FindMatchesAndRunTasks finds nested matches and runs all matched task handlers.

func RunTasks

func RunTasks(
	nestedRouter *Router,
	r *http.Request,
	findNestedMatchesResults *nestedmatcher.Results,
) *TasksResults

RunTasks executes all task handlers for the matched routes in parallel.

IMPORTANT: This function uses object pooling for mux.ReqData objects. The safety of this depends on tasksCtx.RunParallel blocking until all tasks complete. If RunParallel were to return before tasks finish (async dispatch), this would cause use-after-free bugs. The current tasks.Ctx implementation blocks until completion, making this safe.

func RunTasksWithoutPatternMap

func RunTasksWithoutPatternMap(
	nestedRouter *Router,
	r *http.Request,
	findNestedMatchesResults *nestedmatcher.Results,
) *TasksResults

RunTasksWithoutPatternMap executes matched handlers while skipping TasksResults.Map materialization. This is useful for high-throughput callers that consume ordered results only.

func (*TasksResults) HasTaskHandlerAt

func (ntr *TasksResults) HasTaskHandlerAt(i int) bool

HasTaskHandlerAt reports whether the result at i ran a task handler.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL