Documentation
¶
Index ¶
- Variables
- func JoinURL(base, path string, queries ...Query) string
- func SubstituteTemplate(template string, vars map[string]string) string
- func TemplateHelpers(manager *RouteManager, config *TemplateHelperConfig) map[string]any
- func TemplateHelpersWithLocale(manager *RouteManager, config *TemplateHelperConfig, ...) map[string]any
- type Builder
- func (b *Builder) Build() (string, error)
- func (b *Builder) MustBuild() string
- func (b *Builder) WithParam(key string, value any) *Builder
- func (b *Builder) WithParamsMap(values map[string]any) *Builder
- func (b *Builder) WithQuery(key string, value any) *Builder
- func (b *Builder) WithQueryValues(values map[string][]string) *Builder
- func (b *Builder) WithStruct(value any) *Builder
- type Config
- type Configurator
- type FrozenRouteManagerError
- type Group
- func (u *Group) AddRoutes(routes map[string]string) (RouteMutationResult, error)
- func (u *Group) Builder(routeName string) *Builder
- func (u *Group) CollectTemplateVars() map[string]string
- func (u *Group) FQN() string
- func (u *Group) FindTemplateOwner() *Group
- func (u *Group) GetTemplateVar(key string) (string, bool)
- func (u *Group) Group(name string) *Group
- func (u *Group) MustRoute(routeName string) string
- func (u *Group) Navigation(routes []string, params func(route string) Params) ([]NavigationNode, error)
- func (u *Group) RegisterGroup(name, path string, routes map[string]string) (*Group, RouteMutationResult, error)
- func (u *Group) Render(routeName string, params Params, queries ...Query) (string, error)
- func (u *Group) Route(routeName string) (string, error)
- func (u *Group) SetTemplateVar(key, value string) error
- func (u *Group) SetURLTemplate(template string) error
- func (u *Group) Validate(routes []string) error
- type GroupCache
- type GroupConfig
- type GroupValidationError
- type LocaleConfig
- func DefaultLocaleConfig() *LocaleConfig
- func NewFullStackLocaleConfig(defaultLocale string, supportedLocales []string) *LocaleConfig
- func NewHeaderBasedLocaleConfig(defaultLocale string, supportedLocales []string) *LocaleConfig
- func NewMultiStrategyLocaleConfig(defaultLocale string, supportedLocales []string, ...) *LocaleConfig
- func NewURLBasedLocaleConfig(defaultLocale string, supportedLocales []string) *LocaleConfig
- type LocaleDetectionContext
- type LocaleDetectionStrategy
- type LocaleInfo
- type NavigationNode
- type Option
- type Params
- type Query
- type Resolver
- type RootGroupConflictError
- type RouteConflictError
- type RouteConflictErrors
- type RouteConflictPolicy
- type RouteManager
- func (m *RouteManager) AddRoutes(path string, routes map[string]string) (*Group, RouteMutationResult, error)
- func (m *RouteManager) DebugTree() string
- func (m *RouteManager) EnsureGroup(path string) (*Group, error)
- func (m *RouteManager) Freeze()
- func (m *RouteManager) Frozen() bool
- func (m *RouteManager) GetGroup(path string) (*Group, error)
- func (m *RouteManager) Group(path string) *Group
- func (m *RouteManager) Manifest() []RouteManifestEntry
- func (m *RouteManager) MustValidate(groups map[string][]string) *RouteManager
- func (m *RouteManager) RegisterGroup(name, baseURL string, routes map[string]string) (*Group, RouteMutationResult, error)
- func (m *RouteManager) Resolve(groupPath, route string, params Params, query Query) (string, error)
- func (m *RouteManager) ResolveWith(groupPath, route string, params any, query any) (string, error)
- func (m *RouteManager) RoutePath(groupPath, route string) (string, error)
- func (m *RouteManager) RouteTemplate(groupPath, route string) (string, error)
- func (m *RouteManager) Validate(groups map[string][]string) error
- type RouteManifestChange
- type RouteManifestDiff
- type RouteManifestEntry
- type RouteMutationResult
- type TemplateError
- type TemplateHelperConfig
- type TemplateSubstitutionError
- type ValidationError
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrGroupNotFound = errors.New("group not found") ErrRouteNotFound = errors.New("route not found") )
Functions ¶
func SubstituteTemplate ¶
SubstituteTemplate performs string substitution on URL templates using the specified variable map, implementing the {variable_name} placeholder syntax.
Template Syntax:
- Placeholders use curly brace notation: {variable_name}
- Variable names are case-sensitive and can contain letters, numbers, and underscores
- Nested braces are not supported: {{variable}} is treated as literal text
- Missing variables: If a placeholder's variable is not found in the vars map, the placeholder is left unchanged in the output string
Supported Placeholder Examples:
- {protocol} → "https" (if vars["protocol"] = "https")
- {host} → "example.com" (if vars["host"] = "example.com")
- {route_path} → "/about" (built-in dynamic variable)
- {missing} → "{missing}" (unchanged if not in vars map)
Parameters:
- template: The template string containing {variable} placeholders
- vars: Map of variable names to their string values for substitution
Returns:
- string: The template with all found variables substituted, unfound placeholders remain unchanged for debugging purposes
Example:
SubstituteTemplate("{proto}://{host}/{path}", map[string]string{
"proto": "https", "host": "api.example.com", "path": "v1"
})
Returns: "https://api.example.com/v1"
func TemplateHelpers ¶
func TemplateHelpers(manager *RouteManager, config *TemplateHelperConfig) map[string]any
TemplateHelpers returns a map of template helper functions for use with template engines
func TemplateHelpersWithLocale ¶
func TemplateHelpersWithLocale(manager *RouteManager, config *TemplateHelperConfig, localeConfig *LocaleConfig) map[string]any
TemplateHelpersWithLocale returns a map of template helper functions with localization support The returned map can be passed to template.WithTemplateFunc() during engine initialization.
Usage:
manager := NewRouteManager()
config := DefaultTemplateHelperConfig()
localeConfig := DefaultLocaleConfig()
localeConfig.SupportedLocales = []string{"en", "es", "fr"}
localeConfig.LocaleGroups["frontend"] = []string{"en", "es"}
renderer, err := template.NewRenderer(
template.WithTemplateFunc(urlkit.TemplateHelpersWithLocale(manager, config, localeConfig)),
)
Template usage:
{{ url_i18n('frontend', 'user_profile', {'id': user.id}) }}
{{ url_locale('frontend', 'about', 'es') }}
Types ¶
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
func (*Builder) WithParamsMap ¶ added in v0.2.0
func (*Builder) WithQueryValues ¶ added in v0.2.0
func (*Builder) WithStruct ¶ added in v0.2.0
type Config ¶
type Config struct {
Groups []GroupConfig `json:"groups" yaml:"groups"`
}
func (Config) GetGroups ¶
func (c Config) GetGroups() []GroupConfig
GetGroups implements the Configurator interface for the Config struct.
type Configurator ¶
type Configurator interface {
GetGroups() []GroupConfig
}
Configurator defines the interface for route manager configuration. This interface follows the Config Getters pattern and allows for flexible configuration implementations that can be generated automatically.
type FrozenRouteManagerError ¶ added in v0.6.0
func (FrozenRouteManagerError) Error ¶ added in v0.6.0
func (e FrozenRouteManagerError) Error() string
type Group ¶
type Group struct {
// contains filtered or unexported fields
}
Group represents a collection of routes with optional templating capabilities. Groups can be organized in a hierarchy where child groups inherit and can override template variables from their parents.
Template System: Groups support two URL generation modes: 1. Path Concatenation (default): URLs are built by concatenating baseURL + group paths + route 2. Template Rendering: URLs are built using a template string with variable substitution
Template Variable Precedence (highest to lowest priority): - Built in variables (base_url, route_path) - Current group's template variables - Parent group's template variables (recursively up the hierarchy)
Supported Template Syntax: - {variable_name}: Substitutes the variable with its value - {base_url}: Automatically available, contains the root group's base URL - {route_path}: Automatically available, contains the compiled route with parameters
Example (ApiVersioningPattern) ¶
ExampleGroup_apiVersioningPattern demonstrates how to use nested groups for API versioning with backward compatibility.
// Create a route manager for a versioned API
rm := urlkit.NewRouteManager()
// Register the main API group
rm.RegisterGroup("api", "https://api.myservice.com", map[string]string{
"status": "/status",
"health": "/health",
})
api := rm.Group("api")
// Add v1 API routes
v1, _, err := api.RegisterGroup("v1", "/v1", map[string]string{
"users": "/users/:id",
"posts": "/posts",
"comments": "/posts/:postId/comments",
})
if err != nil {
panic(err)
}
// Add v2 API routes with new endpoints
api.RegisterGroup("v2", "/v2", map[string]string{
"users": "/users/:id",
"profiles": "/users/:id/profile",
"posts": "/posts/:id",
"teams": "/teams/:teamId",
})
// Add admin endpoints to v1
v1.RegisterGroup("admin", "/admin", map[string]string{
"dashboard": "/dashboard",
"settings": "/settings/:section",
"reports": "/reports/:type/:date?",
})
// Build URLs for different API versions
// Root API status: https://api.myservice.com/status
statusURL, _ := rm.Group("api").Builder("status").Build()
fmt.Println("API Status URL:", statusURL)
// V1 user endpoint: https://api.myservice.com/v1/users/123
v1UserURL, _ := rm.Group("api").Group("v1").Builder("users").
WithParam("id", "123").
Build()
fmt.Println("V1 User URL:", v1UserURL)
// V2 user profile: https://api.myservice.com/v2/users/123/profile
v2ProfileURL, _ := rm.Group("api").Group("v2").Builder("profiles").
WithParam("id", "123").
Build()
fmt.Println("V2 Profile URL:", v2ProfileURL)
// V1 admin dashboard: https://api.myservice.com/v1/admin/dashboard
adminURL, _ := rm.Group("api").Group("v1").Group("admin").Builder("dashboard").Build()
fmt.Println("Admin Dashboard URL:", adminURL)
// V1 admin reports with optional date: https://api.myservice.com/v1/admin/reports/sales/2023-12
reportsURL, _ := rm.Group("api").Group("v1").Group("admin").Builder("reports").
WithParam("type", "sales").
WithParam("date", "2023-12").
Build()
fmt.Println("Admin Reports URL:", reportsURL)
Output: API Status URL: https://api.myservice.com/status V1 User URL: https://api.myservice.com/v1/users/123 V2 Profile URL: https://api.myservice.com/v2/users/123/profile Admin Dashboard URL: https://api.myservice.com/v1/admin/dashboard Admin Reports URL: https://api.myservice.com/v1/admin/reports/sales/2023-12
Example (InternationalizationPattern) ¶
ExampleGroup_internationalizationPattern demonstrates how to use nested groups for internationalization with localized routes and content.
// Create a route manager for an internationalized website
rm := urlkit.NewRouteManager()
// Register the main frontend group
rm.RegisterGroup("frontend", "https://mywebsite.com", map[string]string{
"home": "/",
})
frontend := rm.Group("frontend")
// Add English locale routes
frontend.RegisterGroup("en", "/en", map[string]string{
"about": "/about-us",
"contact": "/contact",
"products": "/products/:category",
})
// Add Spanish locale routes with localized paths
frontend.RegisterGroup("es", "/es", map[string]string{
"about": "/acerca-de",
"contact": "/contacto",
"products": "/productos/:category",
})
// Build URLs for different locales
// English: https://mywebsite.com/en/about-us
enAboutURL, _ := rm.Group("frontend").Group("en").Builder("about").Build()
fmt.Println("English About URL:", enAboutURL)
// Spanish: https://mywebsite.com/es/acerca-de
esAboutURL, _ := rm.Group("frontend").Group("es").Builder("about").Build()
fmt.Println("Spanish About URL:", esAboutURL)
// English Products with category: https://mywebsite.com/en/products/electronics
enProductsURL, _ := rm.Group("frontend").Group("en").Builder("products").
WithParam("category", "electronics").
Build()
fmt.Println("English Products URL:", enProductsURL)
// Spanish Products with category: https://mywebsite.com/es/productos/electronics
esProductsURL, _ := rm.Group("frontend").Group("es").Builder("products").
WithParam("category", "electronics").
Build()
fmt.Println("Spanish Products URL:", esProductsURL)
Output: English About URL: https://mywebsite.com/en/about-us Spanish About URL: https://mywebsite.com/es/acerca-de English Products URL: https://mywebsite.com/en/products/electronics Spanish Products URL: https://mywebsite.com/es/productos/electronics
func (*Group) AddRoutes ¶
func (u *Group) AddRoutes(routes map[string]string) (RouteMutationResult, error)
AddRoutes dynamically adds new routes to this group at runtime. Routes are immediately compiled and available for URL building. Existing routes with the same name are replaced and recompiled. This method is useful for conditional route registration or dynamic route generation based on configuration.
Parameters:
- routes: a map of route names to path templates (e.g., "users": "/users/:id")
Path templates follow the same syntax as route registration:
- Static segments: "/users/profile"
- Parameters: "/users/:id" or "/posts/:postId/comments/:commentId"
- Optional parameters: "/search/:query?"
Example:
group.AddRoutes(map[string]string{
"webhooks": "/webhooks/:event",
"status": "/status",
})
func (*Group) CollectTemplateVars ¶
CollectTemplateVars aggregates template variables from the entire group hierarchy, implementing a child-overrides-parent precedence system.
The collection process starts from the root group and moves down to the current group, ensuring that variables defined in child groups override those with the same key defined in parent groups. This allows for flexible variable inheritance and specialization at different hierarchy levels.
Variable Precedence Rules (highest to lowest priority):
- Built in dynamic variables (route_path, base_url)
- Current group's templateVars
- Parent groups' templateVars (closer ancestors override distant ones)
Returns:
- map[string]string: A merged map of all template variables with proper precedence applied. Keys are variable names, values are their string values.
Example:
If parent has {"lang": "en", "theme": "light"} and child has {"lang": "es"},
the result will be {"lang": "es", "theme": "light"}.
func (*Group) FQN ¶ added in v0.3.0
FQN returns the group's fully qualified name within the hierarchy (dot notation). Root groups return their own name, while nested groups include their ancestors (e.g., "frontend.en.marketing"). An empty string indicates the group is detached from the manager hierarchy.
func (*Group) FindTemplateOwner ¶
FindTemplateOwner traverses up the group hierarchy to locate the first ancestor group (including the current group) that defines a URL template.
The method performs a depth-first search starting from the current group and moving up the parent chain until it finds a group with a non-empty urlTemplate field.
Returns:
- *Group: The group that owns the URL template, or nil if no template is found in the entire hierarchy chain.
This method is essential for template-based URL construction as it determines which group's template should be used for rendering the final URL.
func (*Group) GetTemplateVar ¶
GetTemplateVar retrieves a template variable value from this group's local variables only. This method does NOT search the hierarchy - it only returns variables directly set on this group. Use CollectTemplateVars() to get the complete set of variables with inheritance applied.
Returns:
- value: the variable value if found
- exists: true if the variable exists in this group's local variables
Example:
value, exists := group.GetTemplateVar("locale")
if exists {
fmt.Printf("Locale is set to: %s\n", value)
}
func (*Group) Group ¶
Group returns a child group by name for fluent API traversal. It panics if the child group is not found.
func (*Group) Navigation ¶ added in v0.2.0
func (u *Group) Navigation(routes []string, params func(route string) Params) ([]NavigationNode, error)
Navigation builds a slice of NavigationNode entries for the provided routes. The params callback can supply per-route parameter maps which are applied before building URLs.
func (*Group) RegisterGroup ¶
func (u *Group) RegisterGroup(name, path string, routes map[string]string) (*Group, RouteMutationResult, error)
RegisterGroup creates and registers a new child group under the current group.
func (*Group) SetTemplateVar ¶
SetTemplateVar sets a template variable that will be available for substitution in URL templates. Template variables follow a hierarchical inheritance pattern where child groups can override parent variables.
Variable Precedence (highest to lowest priority):
- Built in variables (base_url, route_path) - cannot be overridden
- Current group's variables
- Parent group's variables (recursively up the hierarchy)
Common use cases:
- SetTemplateVar("locale", "en-US") for internationalization
- SetTemplateVar("version", "v2") for API versioning
- SetTemplateVar("env", "staging") for environment-specific URLs
- SetTemplateVar("region", "eu-west") for regional deployments
func (*Group) SetURLTemplate ¶
SetURLTemplate sets the URL template string for this group, enabling template-based URL generation. When a template is set, this group becomes a "template owner" and all URL generation for this group and its descendants will use template rendering instead of path concatenation.
Template Syntax:
- Use {variable_name} to insert template variables
- {base_url} is automatically available (the root group's base URL)
- {route_path} is automatically available (the compiled route with parameters)
Example templates:
- "{base_url}/api/{version}{route_path}"
- "{protocol}://{host}/{locale}/{section}{route_path}"
- "{base_url}/{env}/{service}{route_path}"
To disable template rendering and revert to path concatenation, pass an empty string.
type GroupCache ¶
type GroupCache struct {
// contains filtered or unexported fields
}
GroupCache provides simple caching for frequently accessed groups This reduces the overhead of repeated group lookups in template helpers
func NewGroupCache ¶
func NewGroupCache(manager *RouteManager) *GroupCache
NewGroupCache creates a new group cache
func (*GroupCache) Clear ¶
func (gc *GroupCache) Clear()
Clear clears the cache (useful for testing or when routes change)
func (*GroupCache) Get ¶
func (gc *GroupCache) Get(groupName string) *Group
Get retrieves a group from cache or fetches it from the manager
type GroupConfig ¶
type GroupConfig struct {
Name string `json:"name" yaml:"name"`
BaseURL string `json:"base_url,omitempty" yaml:"base_url,omitempty"`
Path string `json:"path,omitempty" yaml:"path,omitempty"`
Routes map[string]string `json:"routes,omitempty" yaml:"routes,omitempty"`
Paths map[string]string `json:"paths,omitempty" yaml:"paths,omitempty"` // legacy support
Groups []GroupConfig `json:"groups,omitempty" yaml:"groups,omitempty"`
// URLTemplate defines the URL structure using placeholder syntax.
// Example: "{protocol}://{host}/{locale}/{section}{route_path}"
// When set, this group becomes a template owner and uses template rendering
// instead of simple path concatenation. Template variables are substituted
// using {variable_name} syntax.
URLTemplate string `json:"url_template,omitempty" yaml:"url_template,omitempty"`
// TemplateVars contains key-value pairs that this group contributes to template rendering.
// Child groups can override parent variables, following a precedence rule where
// child variables take priority over parent variables.
// Special variables:
// - base_url: Automatically set to the group's base URL
// - route_path: Automatically set to the compiled route path with parameters
TemplateVars map[string]string `json:"template_vars,omitempty" yaml:"template_vars,omitempty"`
}
GroupConfig defines the configuration structure for a group when loading from JSON/YAML. It supports both traditional path concatenation and template based URL generation.
type GroupValidationError ¶
type GroupValidationError struct {
MissingRoutes []string
}
func (GroupValidationError) Error ¶
func (g GroupValidationError) Error() string
type LocaleConfig ¶
type LocaleConfig struct {
// Default locale to use when no locale can be detected
DefaultLocale string
// List of supported locales (e.g., ["en", "es", "fr"])
SupportedLocales []string
// Map of group names to their supported locales
// Allows fine-grained control over which locales are available for which groups
// e.g., "frontend" -> ["en", "es"], "api" -> ["en", "fr", "de"]
LocaleGroups map[string][]string
// Custom locale detection function (legacy, for backward compatibility)
// Takes template context data and returns detected locale
LocaleDetector func(context any) string
// Locale detection strategies in priority order
// Uses the new multi-strategy detection system
DetectionStrategies []LocaleDetectionStrategy
// Locale fallback strategy
// When true, falls back to DefaultLocale if detected locale is not supported
// When false, returns error for unsupported locales
EnableLocaleFallback bool
// Hierarchical locale group structure
// When true, supports URLKit's hierarchical groups for locale organization
// e.g., frontend.en.help, frontend.es.help
EnableHierarchicalLocales bool
// Locale validation options
EnableLocaleValidation bool // Validate detected locales against supported list
}
LocaleConfig defines configuration for localization helpers
func DefaultLocaleConfig ¶
func DefaultLocaleConfig() *LocaleConfig
DefaultLocaleConfig returns default locale configuration
func NewFullStackLocaleConfig ¶
func NewFullStackLocaleConfig(defaultLocale string, supportedLocales []string) *LocaleConfig
NewFullStackLocaleConfig creates a comprehensive LocaleConfig with all detection strategies
func NewHeaderBasedLocaleConfig ¶
func NewHeaderBasedLocaleConfig(defaultLocale string, supportedLocales []string) *LocaleConfig
NewHeaderBasedLocaleConfig creates a LocaleConfig optimized for Accept-Language header detection
func NewMultiStrategyLocaleConfig ¶
func NewMultiStrategyLocaleConfig(defaultLocale string, supportedLocales []string, strategies []LocaleDetectionStrategy) *LocaleConfig
NewMultiStrategyLocaleConfig creates a LocaleConfig with multiple detection strategies
func NewURLBasedLocaleConfig ¶
func NewURLBasedLocaleConfig(defaultLocale string, supportedLocales []string) *LocaleConfig
NewURLBasedLocaleConfig creates a LocaleConfig optimized for URL-based locale detection
func (*LocaleConfig) ValidateLocaleConfig ¶
func (c *LocaleConfig) ValidateLocaleConfig() error
ValidateLocaleConfig validates the locale configuration
type LocaleDetectionContext ¶
type LocaleDetectionContext struct {
// TemplateContext is the template data passed to rendering
TemplateContext map[string]any
// URLPath is the current request URL path for URL-based detection
URLPath string
// AcceptLanguage is the Accept-Language header value
AcceptLanguage string
// CookieLocale is the locale from cookie
CookieLocale string
// DefaultLocale is the fallback locale
DefaultLocale string
}
LocaleDetectionContext provides context for locale detection
type LocaleDetectionStrategy ¶
type LocaleDetectionStrategy int
LocaleDetectionStrategy defines different locale detection strategies
const ( // LocaleFromContext extracts locale from template context data LocaleFromContext LocaleDetectionStrategy = iota // LocaleFromURL parses locale from URL path (e.g., /en/path) LocaleFromURL // LocaleFromHeader extracts from Accept-Language header LocaleFromHeader // LocaleFromCookie extracts from locale cookie LocaleFromCookie )
type LocaleInfo ¶
LocaleInfo represents locale information for template helpers
type NavigationNode ¶ added in v0.2.0
type NavigationNode struct {
}
NavigationNode represents a prebuilt navigation entry constructed from a group route. It captures enough information for templates to render menus without recomputing URLs.
type Option ¶ added in v0.6.0
type Option func(*RouteManager)
func WithConflictPolicy ¶ added in v0.6.0
func WithConflictPolicy(policy RouteConflictPolicy) Option
type RootGroupConflictError ¶ added in v0.6.0
type RootGroupConflictError struct {
GroupName string
ExistingBaseURL string
IncomingBaseURL string
}
func (RootGroupConflictError) Error ¶ added in v0.6.0
func (e RootGroupConflictError) Error() string
type RouteConflictError ¶ added in v0.6.0
type RouteConflictError struct {
GroupFQN string
RouteKey string
ExistingTemplate string
IncomingTemplate string
}
func (RouteConflictError) Error ¶ added in v0.6.0
func (e RouteConflictError) Error() string
type RouteConflictErrors ¶ added in v0.6.0
type RouteConflictErrors struct {
Conflicts []RouteConflictError
}
func (RouteConflictErrors) Error ¶ added in v0.6.0
func (e RouteConflictErrors) Error() string
type RouteConflictPolicy ¶ added in v0.6.0
type RouteConflictPolicy string
const ( RouteConflictPolicyError RouteConflictPolicy = "error" RouteConflictPolicyReplace RouteConflictPolicy = "replace" RouteConflictPolicySkip RouteConflictPolicy = "skip" )
type RouteManager ¶
type RouteManager struct {
// contains filtered or unexported fields
}
Example (ConfigurationBasedSetup) ¶
ExampleRouteManager_configurationBasedSetup demonstrates how to load nested groups from JSON configuration for complex application structures.
// Define a comprehensive configuration with nested groups
config := urlkit.Config{
Groups: []urlkit.GroupConfig{
{
Name: "frontend",
BaseURL: "https://myapp.com",
Routes: map[string]string{
"home": "/",
},
Groups: []urlkit.GroupConfig{
{
Name: "en",
Path: "/en",
Routes: map[string]string{
"about": "/about",
"contact": "/contact",
},
Groups: []urlkit.GroupConfig{
{
Name: "help",
Path: "/help",
Routes: map[string]string{
"faq": "/faq",
"support": "/support/:ticketId?",
},
},
},
},
},
},
{
Name: "api",
BaseURL: "https://api.myapp.com",
Routes: map[string]string{
"status": "/status",
},
Groups: []urlkit.GroupConfig{
{
Name: "v1",
Path: "/v1",
Routes: map[string]string{
"users": "/users/:id",
},
},
},
},
},
}
// Create route manager from configuration
manager, err := urlkit.NewRouteManagerFromConfig(&config)
if err != nil {
fmt.Println("failed to load config:", err)
return
}
// Build URLs using the configured nested structure
// Frontend home: https://myapp.com/
homeURL, _ := manager.Group("frontend").Builder("home").Build()
fmt.Println("Home URL:", homeURL)
// English contact page: https://myapp.com/en/contact
contactURL, _ := manager.Group("frontend").Group("en").Builder("contact").Build()
fmt.Println("Contact URL:", contactURL)
// English help FAQ: https://myapp.com/en/help/faq
faqURL, _ := manager.Group("frontend").Group("en").Group("help").Builder("faq").Build()
fmt.Println("FAQ URL:", faqURL)
// English help support with ticket ID: https://myapp.com/en/help/support/T-12345
supportURL, _ := manager.Group("frontend").Group("en").Group("help").Builder("support").
WithParam("ticketId", "T-12345").
Build()
fmt.Println("Support URL:", supportURL)
// API status: https://api.myapp.com/status
apiStatusURL, _ := manager.Group("api").Builder("status").Build()
fmt.Println("API Status URL:", apiStatusURL)
// API v1 users: https://api.myapp.com/v1/users/user-123
usersURL, _ := manager.Group("api").Group("v1").Builder("users").
WithParam("id", "user-123").
WithQuery("include", "profile").
Build()
fmt.Println("API Users URL:", usersURL)
Output: Home URL: https://myapp.com/ Contact URL: https://myapp.com/en/contact FAQ URL: https://myapp.com/en/help/faq Support URL: https://myapp.com/en/help/support/T-12345 API Status URL: https://api.myapp.com/status API Users URL: https://api.myapp.com/v1/users/user-123?include=profile
Example (ValidationWithDotSeparatedRoutes) ¶
ExampleRouteManager_validationWithDotSeparatedRoutes demonstrates how to validate nested group configurations using dot-separated path notation.
// Create a complex nested structure
rm := urlkit.NewRouteManager()
// Register main groups
rm.RegisterGroup("frontend", "https://example.com", map[string]string{
"home": "/",
})
rm.RegisterGroup("api", "https://api.example.com", map[string]string{
"status": "/status",
})
// Add nested groups
frontend := rm.Group("frontend")
frontend.RegisterGroup("en", "/en", map[string]string{
"about": "/about",
"contact": "/contact",
})
api := rm.Group("api")
v1, _, err := api.RegisterGroup("v1", "/v1", map[string]string{
"users": "/users/:id",
"posts": "/posts",
})
if err != nil {
panic(err)
}
v1.RegisterGroup("admin", "/admin", map[string]string{
"dashboard": "/dashboard",
})
// Define expected routes using dot-separated paths for nested groups
expectedRoutes := map[string][]string{
"frontend": {"home"},
"frontend.en": {"about", "contact"},
"api": {"status"},
"api.v1": {"users", "posts"},
"api.v1.admin": {"dashboard"},
}
// Validate the configuration
err = rm.Validate(expectedRoutes)
if err != nil {
fmt.Printf("Validation failed: %v\n", err)
return
}
fmt.Println("✓ All nested groups and routes are properly configured")
// Example of validation failure - missing route
invalidExpected := map[string][]string{
"frontend.en": {"about", "contact", "missing-route"},
"api.v1.admin": {"dashboard", "settings"}, // settings route doesn't exist
"api.v2": {"users"}, // v2 group doesn't exist
}
err = rm.Validate(invalidExpected)
if err != nil {
// Note: Error order may vary due to map iteration
fmt.Println("Expected validation failure occurred (order may vary):", strings.Contains(err.Error(), "validation error"))
}
Output: ✓ All nested groups and routes are properly configured Expected validation failure occurred (order may vary): true
func NewRouteManager ¶
func NewRouteManager(opts ...Option) *RouteManager
func NewRouteManagerFromConfig ¶
func NewRouteManagerFromConfig(config Configurator, opts ...Option) (*RouteManager, error)
NewRouteManagerFromConfig creates a new RouteManager from a Configurator and validates the hierarchy during construction.
func (*RouteManager) AddRoutes ¶ added in v0.2.0
func (m *RouteManager) AddRoutes(path string, routes map[string]string) (*Group, RouteMutationResult, error)
AddRoutes attaches additional routes to an existing group identified by the provided path. Routes in the map are compiled immediately and overwrite any existing routes with the same name. The path supports dot-notation for nested groups.
func (*RouteManager) DebugTree ¶ added in v0.2.0
func (m *RouteManager) DebugTree() string
DebugTree returns a formatted string representing the entire group hierarchy, including routes, templates, and effective template variables for each group. Output is stable (sorted alphabetically) to simplify inspection and diffing.
func (*RouteManager) EnsureGroup ¶ added in v0.2.0
func (m *RouteManager) EnsureGroup(path string) (*Group, error)
EnsureGroup ensures that the full group path exists, creating intermediate groups as needed. The path must start with an existing root group name. Intermediate segments can optionally define a custom path using the syntax "name:/custom-path". Missing segments default to "/name". Returns the final group or an ErrGroupNotFound if the root group does not exist.
func (*RouteManager) Freeze ¶ added in v0.6.0
func (m *RouteManager) Freeze()
func (*RouteManager) Frozen ¶ added in v0.6.0
func (m *RouteManager) Frozen() bool
func (*RouteManager) GetGroup ¶ added in v0.2.0
func (m *RouteManager) GetGroup(path string) (*Group, error)
GetGroup returns the group registered at the given path. The path may reference nested groups using dot-notation (e.g., "frontend.en.marketing"). Returns ErrGroupNotFound when the requested group does not exist.
func (*RouteManager) Group ¶
func (m *RouteManager) Group(path string) *Group
func (*RouteManager) Manifest ¶ added in v0.6.0
func (m *RouteManager) Manifest() []RouteManifestEntry
func (*RouteManager) MustValidate ¶
func (m *RouteManager) MustValidate(groups map[string][]string) *RouteManager
MustValidate calls Validate and panics if validation errors are found.
func (*RouteManager) RegisterGroup ¶
func (m *RouteManager) RegisterGroup(name, baseURL string, routes map[string]string) (*Group, RouteMutationResult, error)
func (*RouteManager) ResolveWith ¶ added in v0.2.0
func (*RouteManager) RoutePath ¶ added in v0.4.0
func (m *RouteManager) RoutePath(groupPath, route string) (string, error)
RoutePath returns the full group path plus the raw route template. It excludes the base URL and does not append query parameters.
func (*RouteManager) RouteTemplate ¶ added in v0.4.0
func (m *RouteManager) RouteTemplate(groupPath, route string) (string, error)
RouteTemplate returns the raw route template for the group. It does not include the group path prefix, base URL, or query parameters.
func (*RouteManager) Validate ¶
func (m *RouteManager) Validate(groups map[string][]string) error
Validate iterates over the given groups and their expected routes, calling each group's Validate method. It returns a ValidationError if any group is missing routes or if a group is entirely missing. Supports dot-separated group paths (e.g., "frontend.en.deep") for nested groups.
type RouteManifestChange ¶ added in v0.6.0
type RouteManifestChange struct {
Before RouteManifestEntry
After RouteManifestEntry
}
type RouteManifestDiff ¶ added in v0.6.0
type RouteManifestDiff struct {
Added []RouteManifestEntry
Removed []RouteManifestEntry
Changed []RouteManifestChange
}
func DiffRouteManifest ¶ added in v0.6.0
func DiffRouteManifest(before, after []RouteManifestEntry) RouteManifestDiff
type RouteManifestEntry ¶ added in v0.6.0
type RouteMutationResult ¶ added in v0.6.0
type RouteMutationResult struct {
Added []string
Replaced []string
Skipped []string
Conflicts []RouteConflictError
}
type TemplateError ¶
type TemplateError struct {
Helper string `json:"helper"`
Type string `json:"type"`
Message string `json:"message"`
Context map[string]any `json:"context,omitempty"`
}
TemplateError represents structured error information for template helpers
type TemplateHelperConfig ¶
type TemplateHelperConfig struct {
// Error reporting configuration
EnableStructuredErrors bool // When true, returns JSON error objects instead of simple strings
EnableErrorLogging bool // When true, logs errors for production debugging
}
TemplateHelperConfig defines configuration for template helpers
func DefaultTemplateHelperConfig ¶
func DefaultTemplateHelperConfig() *TemplateHelperConfig
DefaultTemplateHelperConfig returns default configuration
type TemplateSubstitutionError ¶ added in v0.2.0
type TemplateSubstitutionError struct {
Group string
Route string
TemplateOwner string
Template string
Missing []string
}
TemplateSubstitutionError represents a failure to replace all placeholders in a template.
func (TemplateSubstitutionError) Error ¶ added in v0.2.0
func (e TemplateSubstitutionError) Error() string
type ValidationError ¶
func (ValidationError) Error ¶
func (v ValidationError) Error() string
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
oauth2
command
|
|
|
simple_template
command
|
|
|
templated
command
|
|
|
Package securelink provides secure, expiring URL generation and validation using JWT tokens.
|
Package securelink provides secure, expiring URL generation and validation using JWT tokens. |