Documentation
¶
Overview ¶
Package router implements file-based routing for Vango.
The router provides:
- File-system based route discovery from app/routes/
- Radix tree for efficient route matching
- Parameter extraction with type coercion
- Layout composition and middleware chains
- Code generation for compile-time route registration
File Structure Convention ¶
Routes are defined by Go files in the app/routes/ directory:
app/routes/
├── index.go → GET /
├── about.go → GET /about
├── layout.go → Layout for all routes
├── projects/
│ ├── index.go → GET /projects
│ ├── [id].go → GET /projects/:id
│ └── layout.go → Layout for /projects/*
└── api/
└── users.go → GET/POST /api/users
Note: Bracket notation is allowed in filenames (e.g. [id].go), but NOT recommended for directory names (e.g. projects/[id]/index.go) because Go import paths cannot contain '[' or ']'. For nested param routes, prefer the Go-friendly directory segment: projects/id_/index.go.
Parameters ¶
Dynamic route segments are defined with brackets:
[id].go → :id (string by default) [id:int].go → :id (parsed as int) [...slug].go → *slug (catch-all, []string)
Route Files ¶
Each route file can export specific functions:
func Page(ctx server.Ctx, params Params) vdom.Component // Page handler func Layout(ctx server.Ctx, children Slot) *vdom.VNode // Layout wrapper (Slot is opaque) func Meta(ctx server.Ctx, params Params) PageMeta // Page metadata func Middleware() []Middleware // Route middleware func GET(ctx server.Ctx, params Params) (any, error) // API handlers func POST(ctx server.Ctx, params Params, body T) (any, error)
Usage ¶
scanner := router.NewScanner("app/routes")
routes, err := scanner.Scan()
r := router.NewRouter()
for _, route := range routes {
r.AddPage(route.Path, pageHandler)
}
result, ok := r.Match("GET", "/projects/123")
if ok {
// result.Params["id"] == "123"
// result.PageHandler, result.Layouts, result.Middleware available
}
Index ¶
- Variables
- func ActiveLink(href string, activeClass string, exactMatch bool, children ...any) *vdom.VNode
- func CanonicalizeAndValidateNavPath(path string) (string, error)
- func ComposeMiddleware(ctx server.Ctx, mw []Middleware, handler func() error) error
- func DataLink() vdom.Attrdeprecated
- func DecodePathSegments(path string) ([]string, error)
- func DecodeSegment(segment string, isCatchAll bool) (string, error)
- func FormatValidationError(err ValidationError) string
- func Link(href string, children ...any) *vdom.VNodedeprecated
- func LinkWithPrefetch(href string, children ...any) *vdom.VNodedeprecated
- func NavLink(href string, children ...any) *vdom.VNodedeprecated
- func Prefetch() vdom.Attr
- func Redirect(ctx server.Ctx, path string, code int)
- func RedirectExternal(ctx server.Ctx, url string, code int)
- func SortBySpecificity(routes []ScannedRoute)
- func SplitPathAndQuery(input string) (path, query string)
- func ValidateInt(value string) error
- func ValidateParam(value, paramType string) error
- func ValidateUUID(value string) error
- func VangoLink() vdom.Attr
- type APIEndpoint
- type APIHandler
- type CanonicalizeResult
- type ErrorHandler
- type FieldInfo
- type FileDiff
- type GenerationResult
- type Generator
- type GeneratorConfig
- type GeneratorWithConfig
- func (g *GeneratorWithConfig) Generate() (*GenerationResult, error)
- func (g *GeneratorWithConfig) GenerateToPath(outputPath string) (*GenerationResult, error)
- func (g *GeneratorWithConfig) Routes() []ScannedRoute
- func (g *GeneratorWithConfig) Scan() error
- func (g *GeneratorWithConfig) VerifyUpToDate() (*VerifyResult, error)
- type Handler
- type HandlerFunc
- type HandlerRegistry
- type LayoutHandler
- type MatchResult
- type Middleware
- func Chain(middleware ...Middleware) Middleware
- func Logger(logger *slog.Logger) Middleware
- func Only(condition func(ctx server.Ctx) bool, mw Middleware) Middleware
- func RateLimit(maxPerSecond int) Middleware
- func Recover(onPanic func(ctx server.Ctx, recovered any)) Middleware
- func Skip(condition func(ctx server.Ctx) bool, mw Middleware) Middleware
- func Timeout(duration time.Duration) Middleware
- func WithValue(key, value any) Middleware
- type MiddlewareFunc
- type MultiValidationError
- type NavigateOption
- type NavigateOptions
- type NavigationRequest
- type Navigator
- type OpenAPIComponents
- type OpenAPIGenerator
- type OpenAPIInfo
- type OpenAPIMediaType
- type OpenAPIOperation
- type OpenAPIParameter
- type OpenAPIPath
- type OpenAPIRequestBody
- type OpenAPIResponse
- type OpenAPISchema
- type OpenAPISpec
- type OpenAPISpecInfo
- type PageHandler
- type PageMeta
- type ParamDef
- type ParamParser
- type RouteNode
- type RouteOption
- type Router
- func (r *Router) API(method, path string, handler APIHandler, opts ...RouteOption)
- func (r *Router) AddAPI(path, method string, handler APIHandler)
- func (r *Router) AddLayout(path string, handler LayoutHandler)
- func (r *Router) AddMiddleware(path string, mw ...Middleware)
- func (r *Router) AddPage(path string, handler PageHandler)
- func (r *Router) BuildFromScanned(routes []ScannedRoute, registry *HandlerRegistry)
- func (r *Router) ErrorPage() ErrorHandler
- func (r *Router) Layout(path string, handler LayoutHandler)
- func (r *Router) Match(method, path string) (*MatchResult, bool)
- func (r *Router) Middleware(path string, mw ...Middleware)
- func (r *Router) MiddlewareForPath(path string) []server.RouteMiddleware
- func (r *Router) NotFound() PageHandler
- func (r *Router) Page(path string, handler PageHandler, opts ...RouteOption)
- func (r *Router) ServeHTTP(ctx server.Ctx) (*MatchResult, bool)
- func (r *Router) SetErrorPage(handler ErrorHandler)
- func (r *Router) SetNotFound(handler PageHandler)
- func (r *Router) Use(mw ...Middleware)
- type RouterAdapter
- type ScanOptions
- type ScannedRoute
- type Scanner
- type Slot
- type TypeInfo
- type ValidationError
- type ValidationErrorType
- type Validator
- type VerifyResult
Constants ¶
This section is empty.
Variables ¶
var ( ErrInvalidPath = routepath.ErrInvalidPath ErrBackslashInPath = routepath.ErrBackslashInPath ErrNullByteInPath = routepath.ErrNullByteInPath ErrInvalidPercentEscape = routepath.ErrInvalidPercentEscape ErrPathEscapesRoot = routepath.ErrPathEscapesRoot ErrEncodedSlashInSegment = routepath.ErrEncodedSlashInSegment )
Path canonicalization errors.
var ErrRateLimited = errors.New("rate limit exceeded")
ErrRateLimited is returned when the rate limit is exceeded.
Functions ¶
func ActiveLink ¶
ActiveLink creates a link with custom active class handling via data attributes. This is for power users who need custom active class names or client-side active state detection.
For most use cases, prefer el.NavLink(ctx, path, children...) which uses server-side path matching to add the "active" class directly.
The activeClass is set via data-active-class attribute. The exactMatch parameter controls whether the match must be exact (data-active-exact).
func CanonicalizeAndValidateNavPath ¶
CanonicalizeAndValidateNavPath canonicalizes and validates a navigation path.
func ComposeMiddleware ¶
func ComposeMiddleware(ctx server.Ctx, mw []Middleware, handler func() error) error
ComposeMiddleware builds a handler chain from middleware and a final handler. Middleware is executed in order (first to last), with the handler at the end.
func DecodePathSegments ¶
DecodePathSegments decodes all segments of a path.
func DecodeSegment ¶
DecodeSegment decodes a single path segment.
func FormatValidationError ¶
func FormatValidationError(err ValidationError) string
FormatValidationError formats a validation error for display. Per the spec, errors should be formatted clearly:
ERROR: Duplicate route detected /projects/[id].go → /projects/:id /projects/id_.go → /projects/:id
func Link
deprecated
Link creates an anchor element with SPA navigation enabled. When clicked, the thin client intercepts and sends a navigate event to the server instead of performing a full page reload.
Deprecated: Use el.Link() instead. With the dot import of el, this is simply Link("/path", Text("label")). This function remains for backwards compatibility but will be removed in a future version.
func LinkWithPrefetch
deprecated
LinkWithPrefetch creates a link that prefetches the target page on hover. This provides faster navigation by loading the target page before the user clicks.
Deprecated: Use el.LinkPrefetch() instead. With the dot import of el, this is simply LinkPrefetch("/path", Text("label")). This function remains for backwards compatibility but will be removed in a future version.
func NavLink
deprecated
NavLink creates a link with default active class handling.
Deprecated: Use el.NavLink(ctx, path, children...) instead. The new NavLink uses server-side path matching which works with SSR and doesn't require client-side JavaScript. This function remains for backwards compatibility but will be removed in a future version.
func Prefetch ¶
Prefetch creates a prefetch attribute for links. Add this to any anchor element to enable hover prefetching.
Example:
A(Href("/about"), Prefetch(), Text("About"))
func Redirect ¶
Redirect sends an HTTP redirect response (relative paths only). This should only be used for initial page loads, not WebSocket navigations.
func RedirectExternal ¶
RedirectExternal sends an HTTP redirect to an external URL. External redirects require an explicit allowlist.
func SortBySpecificity ¶
func SortBySpecificity(routes []ScannedRoute)
SortBySpecificity sorts routes by specificity for proper matching order. Per Section 1.3.1:
- Static segments > typed parameters > plain parameters > catch-all
- More specific routes should be matched first
Order (most specific first):
- Static routes (/users/profile)
- Routes with typed params (/users/:id where id is int)
- Routes with plain params (/users/:id where id is string)
- Catch-all routes (/users/*path)
func SplitPathAndQuery ¶
SplitPathAndQuery splits a path into path and query components. The query is returned without the leading "?".
func ValidateInt ¶
ValidateInt validates that a string is a valid integer.
func ValidateParam ¶
ValidateParam validates a parameter value against its expected type.
func ValidateUUID ¶
ValidateUUID validates that a string is a valid UUID.
Types ¶
type APIEndpoint ¶
type APIEndpoint struct {
Path string
Method string
FuncName string
Package string
Description string
Params []ParamDef
RequestType *TypeInfo
ResponseType *TypeInfo
}
APIEndpoint represents a discovered API endpoint.
type APIHandler ¶
APIHandler handles an API request, returning data or an error. The params parameter is a typed params struct, body is the decoded request body.
type CanonicalizeResult ¶
type CanonicalizeResult = routepath.CanonicalizeResult
CanonicalizeResult contains the result of path canonicalization.
func CanonicalizePath ¶
func CanonicalizePath(input string) (CanonicalizeResult, error)
CanonicalizePath normalizes a URL path according to the routing contract.
type ErrorHandler ¶
ErrorHandler handles error pages.
type FileDiff ¶
type FileDiff struct {
// Path is the relative path to the file
Path string `json:"path"`
// Status is one of: "missing", "changed"
Status string `json:"status"`
}
FileDiff describes a mismatch between generated and existing files.
type GenerationResult ¶
type GenerationResult struct {
// OutputFile is the path to the generated file
OutputFile string `json:"outputFile"`
// RouteCount is the total number of routes discovered
RouteCount int `json:"routeCount"`
// PageCount is the number of page routes
PageCount int `json:"pageCount"`
// APICount is the number of API routes
APICount int `json:"apiCount"`
// LayoutCount is the number of layouts
LayoutCount int `json:"layoutCount"`
// MiddlewareCount is the number of middleware registrations
MiddlewareCount int `json:"middlewareCount"`
}
GenerationResult contains the results of route generation.
type Generator ¶
type Generator struct {
// contains filtered or unexported fields
}
Generator generates Go code for registering routes.
func NewGenerator ¶
func NewGenerator(routes []ScannedRoute, modulePath string) *Generator
NewGenerator creates a new code generator.
type GeneratorConfig ¶
type GeneratorConfig struct {
// RoutesDir is the directory to scan for route files (e.g., "app/routes")
RoutesDir string
// ModulePath is the Go module path (e.g., "github.com/example/myapp")
ModulePath string
// OutputPath is the output file path (default: {RoutesDir}/routes_gen.go)
OutputPath string
}
GeneratorConfig configures the route code generator.
type GeneratorWithConfig ¶
type GeneratorWithConfig struct {
// contains filtered or unexported fields
}
GeneratorWithConfig holds configuration and state for code generation. Use this for verification workflows; use NewGenerator for simple generation.
func NewGeneratorWithConfig ¶
func NewGeneratorWithConfig(config GeneratorConfig) *GeneratorWithConfig
NewGeneratorWithConfig creates a new generator from configuration.
func (*GeneratorWithConfig) Generate ¶
func (g *GeneratorWithConfig) Generate() (*GenerationResult, error)
Generate scans routes (if needed) and generates the routes_gen.go file.
func (*GeneratorWithConfig) GenerateToPath ¶
func (g *GeneratorWithConfig) GenerateToPath(outputPath string) (*GenerationResult, error)
GenerateToPath generates routes to a specific output path.
func (*GeneratorWithConfig) Routes ¶
func (g *GeneratorWithConfig) Routes() []ScannedRoute
Routes returns the scanned routes.
func (*GeneratorWithConfig) Scan ¶
func (g *GeneratorWithConfig) Scan() error
Scan populates routes by scanning the configured routes directory.
func (*GeneratorWithConfig) VerifyUpToDate ¶
func (g *GeneratorWithConfig) VerifyUpToDate() (*VerifyResult, error)
VerifyUpToDate checks whether generated routes match the current source files. Returns an error with code VANGO.ROUTES.OUT_OF_DATE if routes are stale.
type Handler ¶
Handler is a function that handles a request context. This is the base type for all route handlers in middleware chains. It's compatible with the signature expected by middleware patterns.
type HandlerFunc ¶
type HandlerFunc = Handler
HandlerFunc is an alias for Handler for naming consistency with http.HandlerFunc.
type HandlerRegistry ¶
type HandlerRegistry struct {
Pages map[string]PageHandler
Layouts map[string]LayoutHandler
APIs map[string]map[string]APIHandler // path -> method -> handler
MW map[string][]Middleware
}
BuildFromScanned builds the router from scanned routes and a handler registry. The registry maps file paths to handler functions.
type LayoutHandler ¶
LayoutHandler wraps child content in a layout.
type MatchResult ¶
type MatchResult struct {
// PageHandler is the handler for page routes
PageHandler PageHandler
// APIHandler is the handler for API routes
APIHandler APIHandler
// Layouts are hierarchical layouts collected from app.Layout() calls (root to leaf)
Layouts []LayoutHandler
// PageLayouts are explicit layouts from app.Page(..., layouts)
// These are NOT inherited - they replace hierarchical layouts when HasPageLayouts is true
PageLayouts []LayoutHandler
// HasPageLayouts distinguishes "unset" vs "explicitly empty"
// When true, PageLayouts should be used instead of Layouts
HasPageLayouts bool
// Middleware is the combined middleware chain
Middleware []Middleware
// Params are the extracted route parameters
Params map[string]string
// Route is the matched route definition
Route *ScannedRoute
// MethodNotAllowed indicates the path matched an API route, but the requested
// method did not match any registered handler.
MethodNotAllowed bool
// AllowedMethods is the set of allowed HTTP methods for the matched API path.
// Only meaningful when MethodNotAllowed is true.
AllowedMethods []string
}
MatchResult contains the result of matching a path against the router. Implements server.RouteMatch interface.
func (*MatchResult) GetLayoutHandlers ¶
func (m *MatchResult) GetLayoutHandlers() []server.LayoutHandler
GetLayoutHandlers implements server.RouteMatch.
func (*MatchResult) GetMiddleware ¶
func (m *MatchResult) GetMiddleware() []server.RouteMiddleware
GetMiddleware implements server.RouteMatch.
func (*MatchResult) GetPageHandler ¶
func (m *MatchResult) GetPageHandler() server.PageHandler
GetPageHandler implements server.RouteMatch.
func (*MatchResult) GetParams ¶
func (m *MatchResult) GetParams() map[string]string
GetParams implements server.RouteMatch.
type Middleware ¶
type Middleware interface {
// Handle processes the request and optionally calls next.
// Return an error to stop the chain and report an error.
// Return nil without calling next to stop the chain without error.
Handle(ctx server.Ctx, next func() error) error
}
Middleware processes requests before they reach the handler.
func Chain ¶
func Chain(middleware ...Middleware) Middleware
Chain creates a middleware that combines multiple middleware in order.
func Logger ¶
func Logger(logger *slog.Logger) Middleware
Logger returns middleware that logs each event with timing information. This is for Vango event-loop logging (Layer 2), not HTTP request logging.
func Only ¶
func Only(condition func(ctx server.Ctx) bool, mw Middleware) Middleware
Only is a middleware that runs only if a condition is true.
func RateLimit ¶
func RateLimit(maxPerSecond int) Middleware
RateLimit returns middleware that limits events per session. maxPerSecond specifies the maximum number of events allowed per second. Exceeding the limit returns ErrRateLimited.
func Recover ¶
func Recover(onPanic func(ctx server.Ctx, recovered any)) Middleware
Recover returns middleware that recovers from panics. The onPanic callback is called with the recovered value and can log or handle it.
func Skip ¶
func Skip(condition func(ctx server.Ctx) bool, mw Middleware) Middleware
Skip is a middleware that skips to the next middleware based on a condition.
func Timeout ¶
func Timeout(duration time.Duration) Middleware
Timeout returns middleware that times out after the specified duration. Note: This only affects the handler execution, not the full event processing.
func WithValue ¶
func WithValue(key, value any) Middleware
WithValue returns middleware that sets a context value for the request. The value is available to subsequent middleware and handlers via ctx.Value().
type MiddlewareFunc ¶
MiddlewareFunc is a function adapter for Middleware.
type MultiValidationError ¶
type MultiValidationError struct {
Errors []ValidationError
}
MultiValidationError wraps multiple validation errors.
func (*MultiValidationError) Error ¶
func (e *MultiValidationError) Error() string
type NavigateOption ¶
type NavigateOption func(*NavigateOptions)
NavigateOption is a functional option for Navigate.
func WithParams ¶
func WithParams(params map[string]any) NavigateOption
WithParams adds query parameters to the navigation URL.
func WithPrefetch ¶
func WithPrefetch() NavigateOption
WithPrefetch enables prefetching for this navigation.
func WithReplace ¶
func WithReplace() NavigateOption
WithReplace replaces the current history entry instead of pushing.
func WithoutScroll ¶
func WithoutScroll() NavigateOption
WithoutScroll disables scrolling to top after navigation.
type NavigateOptions ¶
type NavigateOptions struct {
Replace bool
Params map[string]any
// Defaults to true.
Scroll bool
Prefetch bool
}
NavigateOptions configures navigation behavior.
type NavigationRequest ¶
type NavigationRequest struct {
}
NavigationRequest represents a pending navigation.
func (*NavigationRequest) BuildURL ¶
func (nr *NavigationRequest) BuildURL() (string, error)
BuildURL constructs the full URL for a navigation request.
type Navigator ¶
type Navigator interface {
Navigate(path string, opts ...NavigateOption)
Back()
Forward()
}
Navigator handles client-side navigation. It is typically obtained from the request context.
func NewNavigator ¶
NewNavigator creates a new navigator for the given context.
type OpenAPIComponents ¶
type OpenAPIComponents struct {
Schemas map[string]*OpenAPISchema `json:"schemas,omitempty"`
}
OpenAPIComponents contains reusable components.
type OpenAPIGenerator ¶
type OpenAPIGenerator struct {
// contains filtered or unexported fields
}
OpenAPIGenerator generates OpenAPI 3.0 specifications from API routes.
func NewOpenAPIGenerator ¶
func NewOpenAPIGenerator(routesDir, modulePath string, info OpenAPIInfo) *OpenAPIGenerator
NewOpenAPIGenerator creates a new OpenAPI generator.
func (*OpenAPIGenerator) Generate ¶
func (g *OpenAPIGenerator) Generate() ([]byte, error)
Generate creates an OpenAPI specification from the API routes.
type OpenAPIInfo ¶
OpenAPIInfo contains API metadata.
type OpenAPIMediaType ¶
type OpenAPIMediaType struct {
Schema *OpenAPISchema `json:"schema,omitempty"`
}
OpenAPIMediaType represents media type content.
type OpenAPIOperation ¶
type OpenAPIOperation struct {
Summary string `json:"summary,omitempty"`
Description string `json:"description,omitempty"`
OperationID string `json:"operationId,omitempty"`
Tags []string `json:"tags,omitempty"`
Parameters []OpenAPIParameter `json:"parameters,omitempty"`
RequestBody *OpenAPIRequestBody `json:"requestBody,omitempty"`
Responses map[string]OpenAPIResponse `json:"responses"`
}
OpenAPIOperation represents an HTTP operation.
type OpenAPIParameter ¶
type OpenAPIParameter struct {
Name string `json:"name"`
In string `json:"in"` // path, query, header
Description string `json:"description,omitempty"`
Required bool `json:"required,omitempty"`
Schema *OpenAPISchema `json:"schema"`
}
OpenAPIParameter represents a request parameter.
type OpenAPIPath ¶
type OpenAPIPath map[string]*OpenAPIOperation
OpenAPIPath represents path operations.
type OpenAPIRequestBody ¶
type OpenAPIRequestBody struct {
Description string `json:"description,omitempty"`
Required bool `json:"required,omitempty"`
Content map[string]OpenAPIMediaType `json:"content"`
}
OpenAPIRequestBody represents a request body.
type OpenAPIResponse ¶
type OpenAPIResponse struct {
Description string `json:"description"`
Content map[string]OpenAPIMediaType `json:"content,omitempty"`
}
OpenAPIResponse represents a response.
type OpenAPISchema ¶
type OpenAPISchema struct {
Type string `json:"type,omitempty"`
Format string `json:"format,omitempty"`
Items *OpenAPISchema `json:"items,omitempty"`
Properties map[string]*OpenAPISchema `json:"properties,omitempty"`
Required []string `json:"required,omitempty"`
Ref string `json:"$ref,omitempty"`
}
OpenAPISchema represents a JSON schema.
type OpenAPISpec ¶
type OpenAPISpec struct {
OpenAPI string `json:"openapi"`
Info OpenAPISpecInfo `json:"info"`
Paths map[string]OpenAPIPath `json:"paths"`
Components *OpenAPIComponents `json:"components,omitempty"`
}
OpenAPISpec represents an OpenAPI 3.0 specification.
type OpenAPISpecInfo ¶
type OpenAPISpecInfo struct {
Title string `json:"title"`
Description string `json:"description,omitempty"`
Version string `json:"version"`
}
OpenAPISpecInfo contains API info.
type PageHandler ¶
PageHandler handles a page request, returning a component to render.
type PageMeta ¶
type PageMeta struct {
Title string
Description string
Keywords []string
OGImage string
OGTitle string
OGDesc string
Canonical string
Robots string
}
PageMeta contains page metadata for SEO.
type ParamDef ¶
type ParamDef struct {
// Name is the parameter name (e.g., "id")
Name string
// Type is the parameter type (e.g., "int", "string", "uuid")
Type string
// ExplicitType is the explicit type annotation from the route segment, if any.
// Example: "[id:int]" -> "int". Empty means the type was inferred by convention.
ExplicitType string
// Segment is the original segment (e.g., "[id]", "[id:int]")
Segment string
}
ParamDef defines a route parameter.
type ParamParser ¶
type ParamParser struct{}
ParamParser parses string parameters into typed struct fields.
func NewParamParser ¶
func NewParamParser() *ParamParser
NewParamParser creates a new parameter parser.
type RouteNode ¶
type RouteNode struct {
// contains filtered or unexported fields
}
RouteNode is a node in the radix tree.
type RouteOption ¶
type RouteOption func(*routeOptions)
RouteOption configures route registration. Used for param type constraints, page layouts, etc.
func WithPageLayouts ¶
func WithPageLayouts(layouts ...LayoutHandler) RouteOption
WithPageLayouts sets explicit layouts for a page (not inherited). When set, these layouts are used instead of hierarchical layouts from app.Layout() calls. This allows different sections of an app to use different layouts.
Example:
// Marketing pages use MarketingLayout
r.Page("/", HomePage, router.WithPageLayouts(MarketingLayout))
// App pages use AppLayout (completely different)
r.Page("/app/dashboard", DashboardPage, router.WithPageLayouts(AppLayout))
func WithParamType ¶
func WithParamType(param, typ string) RouteOption
WithParamType specifies the type constraint for a route parameter. This allows specifying the type separately from the path pattern.
Example:
r.Page("/users/:id", users.ShowPage, router.WithParamType("id", "int"))
This is equivalent to using the inline type syntax:
r.Page("/users/:id:int", users.ShowPage)
func WithParamValidator ¶
func WithParamValidator(param string, fn func(string) error) RouteOption
WithParamValidator sets a validation function for a route parameter. When set, the validator is used during route matching to determine whether a parameter segment is considered a match (return nil) or rejected (return error).
type Router ¶
type Router struct {
// contains filtered or unexported fields
}
Router manages route matching and handler dispatch.
func (*Router) API ¶
func (r *Router) API(method, path string, handler APIHandler, opts ...RouteOption)
API registers an API handler for a method and path. This is the spec-compliant alias for AddAPI. Note: method comes first to match natural reading order ("GET /api/health").
Example:
r.API("GET", "/api/health", api.HealthGET)
r.API("POST", "/api/users", api.UsersPOST)
func (*Router) AddAPI ¶
func (r *Router) AddAPI(path, method string, handler APIHandler)
AddAPI registers an API handler for a path and method.
func (*Router) AddLayout ¶
func (r *Router) AddLayout(path string, handler LayoutHandler)
AddLayout registers a layout handler for a path.
func (*Router) AddMiddleware ¶
func (r *Router) AddMiddleware(path string, mw ...Middleware)
AddMiddleware adds middleware to a specific path.
func (*Router) AddPage ¶
func (r *Router) AddPage(path string, handler PageHandler)
AddPage registers a page handler for a path.
func (*Router) BuildFromScanned ¶
func (r *Router) BuildFromScanned(routes []ScannedRoute, registry *HandlerRegistry)
BuildFromScanned populates the router from scanned routes.
func (*Router) ErrorPage ¶
func (r *Router) ErrorPage() ErrorHandler
ErrorPage returns the error page handler.
func (*Router) Layout ¶
func (r *Router) Layout(path string, handler LayoutHandler)
Layout registers a layout handler for a path. This is the spec-compliant alias for AddLayout.
func (*Router) Match ¶
func (r *Router) Match(method, path string) (*MatchResult, bool)
Match finds the handler for a path.
func (*Router) Middleware ¶
func (r *Router) Middleware(path string, mw ...Middleware)
Middleware adds middleware to a specific path. This is the spec-compliant alias for AddMiddleware.
func (*Router) MiddlewareForPath ¶
func (r *Router) MiddlewareForPath(path string) []server.RouteMiddleware
MiddlewareForPath returns the route middleware chain that applies to path. This includes global middleware and middleware on the longest matching route prefix. Unlike Match, this does not require a terminal page/API handler.
func (*Router) Page ¶
func (r *Router) Page(path string, handler PageHandler, opts ...RouteOption)
Page registers a page handler for a path. This is the spec-compliant alias for AddPage. Optional RouteOption arguments can specify parameter type constraints or page layouts.
Example:
r.Page("/users/:id", users.ShowPage)
r.Page("/users/:id", users.ShowPage, router.WithParamType("id", "int"))
r.Page("/app/dashboard", DashboardPage, router.WithPageLayouts(AppLayout))
func (*Router) ServeHTTP ¶
func (r *Router) ServeHTTP(ctx server.Ctx) (*MatchResult, bool)
ServeHTTP implements http.Handler for the router. This provides basic HTTP routing without WebSocket features.
func (*Router) SetErrorPage ¶
func (r *Router) SetErrorPage(handler ErrorHandler)
SetErrorPage sets the error page handler.
func (*Router) SetNotFound ¶
func (r *Router) SetNotFound(handler PageHandler)
SetNotFound sets the 404 handler.
func (*Router) Use ¶
func (r *Router) Use(mw ...Middleware)
Use adds global middleware that applies to all routes.
type RouterAdapter ¶
type RouterAdapter struct {
*Router
}
RouterAdapter wraps Router to implement server.Router interface. This adapter is needed because the server package defines its own PageHandler type to avoid import cycles.
func NewRouterAdapter ¶
func NewRouterAdapter(r *Router) *RouterAdapter
NewRouterAdapter creates a new adapter for use with server.Session.SetRouter().
func (*RouterAdapter) Match ¶
func (a *RouterAdapter) Match(method, path string) (server.RouteMatch, bool)
Match implements server.Router interface.
func (*RouterAdapter) NotFound ¶
func (a *RouterAdapter) NotFound() server.PageHandler
NotFound implements server.Router interface.
type ScanOptions ¶
type ScanOptions struct {
// Validate enables route validation (duplicate detection, constraint conflicts, etc.)
Validate bool
// Sort enables specificity sorting (static > typed > plain > catch-all)
Sort bool
}
ScanOptions configures scanning behavior.
type ScannedRoute ¶
type ScannedRoute struct {
// Path is the URL pattern (e.g., "/projects/:id")
Path string
// FilePath is the source file path
FilePath string
// Package is the Go package name
Package string
// Params are the route parameters
Params []ParamDef
// ParamStructTypes maps route param name -> canonical type derived from the
// handler's params struct (when available). Used for validation.
ParamStructTypes map[string]string
// HasPage indicates the file exports a page handler function (e.g., IndexPage)
HasPage bool
// HandlerName is the actual name of the page handler function (e.g., "IndexPage", "ShowPage")
HandlerName string
// HasLayout indicates the file exports a Layout function
HasLayout bool
// HasMeta indicates the file exports a Meta function
HasMeta bool
// HasMiddleware indicates the file exports a Middleware variable or function
HasMiddleware bool
// MiddlewareIsFunc indicates the route exports a Middleware() function.
MiddlewareIsFunc bool
// MiddlewareIsVar indicates the route exports a Middleware variable.
MiddlewareIsVar bool
// Methods lists HTTP methods for API routes (GET, POST, etc.)
Methods []string
// APIHandlers maps HTTP method to the exported Go function name.
// Example: {"GET": "GET"} or {"GET": "HealthGET"}.
APIHandlers map[string]string
// IsAPI indicates this is an API route (returns JSON)
IsAPI bool
// IsCatchAll indicates this is a catch-all route ([...slug])
IsCatchAll bool
}
ScannedRoute represents a route discovered by the scanner.
func ValidateAndSort ¶
func ValidateAndSort(routes []ScannedRoute) ([]ScannedRoute, error)
ValidateAndSort validates routes and sorts them by specificity. This is the main entry point for the scanner to call.
type Scanner ¶
type Scanner struct {
// contains filtered or unexported fields
}
Scanner scans a directory for route files.
func (*Scanner) Scan ¶
func (s *Scanner) Scan() ([]ScannedRoute, error)
Scan reads all route files and returns route definitions. Routes are validated and sorted by specificity.
func (*Scanner) ScanWithOptions ¶
func (s *Scanner) ScanWithOptions(opts ScanOptions) ([]ScannedRoute, error)
ScanWithOptions reads all route files with configurable validation and sorting.
type Slot ¶
Slot represents the child content passed to a layout. It is an opaque container that can be rendered by VDOM elements.
type ValidationError ¶
type ValidationError struct {
// Type is the error category
Type ValidationErrorType
// Message is the human-readable error message
Message string
// Files are the source files involved
Files []string
// Path is the conflicting URL pattern
Path string
// Details contains additional error-specific information
Details string
}
ValidationError represents a route validation error.
func (ValidationError) Error ¶
func (e ValidationError) Error() string
type ValidationErrorType ¶
type ValidationErrorType string
ValidationErrorType categorizes validation errors.
const ( // ErrorInvalidGoFilename indicates a route file won't be compiled by Go. // The Go toolchain ignores files whose basename starts with '_' or '.'. ErrorInvalidGoFilename ValidationErrorType = "INVALID_GO_FILENAME" // ErrorInvalidGoImportPath indicates a route directory name will produce an // invalid Go import path in generated routes_gen.go (e.g. directories containing '[' or ']'). ErrorInvalidGoImportPath ValidationErrorType = "INVALID_GO_IMPORT_PATH" // ErrorDuplicateRoute indicates multiple files resolve to the same URL pattern. // Example: [id].go and id_.go both resolve to /:id ErrorDuplicateRoute ValidationErrorType = "DUPLICATE_ROUTE" // ErrorParamConstraintConflict indicates the same param has different type constraints. // Example: [id:int].go and [id].go at the same path ErrorParamConstraintConflict ValidationErrorType = "PARAM_CONSTRAINT_CONFLICT" // ErrorAPIAmbiguity indicates both bare (GET) and prefixed (HealthGET) handlers exist. // Example: Both GET() and HealthGET() exported in /api/health.go ErrorAPIAmbiguity ValidationErrorType = "API_AMBIGUITY" // ErrorMiddlewareAmbiguity indicates both Middleware() and Middleware var exist. // Example: middleware.go exports both `func Middleware()` and `var Middleware`. ErrorMiddlewareAmbiguity ValidationErrorType = "MIDDLEWARE_AMBIGUITY" // ErrorParamTypeMismatch indicates annotation type differs from Params struct field type. // Example: [id:int].go but Params struct has id as string ErrorParamTypeMismatch ValidationErrorType = "PARAM_TYPE_MISMATCH" )
type Validator ¶
type Validator struct {
// contains filtered or unexported fields
}
Validator validates scanned routes for conflicts and errors. Per Section 1.3 and 1.6 of the Routing Spec.
func NewValidator ¶
func NewValidator(routes []ScannedRoute) *Validator
NewValidator creates a new route validator.
type VerifyResult ¶
type VerifyResult struct {
// Current is true if the generated routes match the existing file
Current bool `json:"current"`
// Differences lists files that differ from expected
Differences []FileDiff `json:"differences,omitempty"`
}
VerifyResult contains the result of routes verification.