router

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Mar 12, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

README

Router Package

The router package provides a priority-based routing engine for the Cube proxy, enabling sophisticated request matching and forwarding to configurable target URLs.

Overview

The router matches incoming HTTP requests against a set of configurable rules and determines the appropriate target URL. Routes are evaluated in priority order, with support for pattern matching on multiple request attributes (path, method, headers, query parameters, and request body).

Core Concepts

Route Rule

A RouteRule defines a complete routing configuration with the following properties:

  • Name: Unique identifier for the route (must be alphanumeric with hyphens or underscores)
  • TargetURL: The destination URL where matching requests are forwarded
  • Matchers: Conditions that must all match for the route to be selected (AND logic)
  • Priority: Determines evaluation order; higher values are checked first (0-1000)
  • DefaultRule: If true, matches when no other rules match
  • StripPrefix: Optional path prefix to remove before forwarding
  • Enabled: Optional flag to skip disabled routes (defaults to true)
Route Matching

Routes are evaluated in descending priority order. All matchers within a route must match (AND logic) for the route to be selected. The router supports matching on:

  • Path: Exact or regex patterns
  • HTTP Method: GET, POST, PUT, etc.
  • Headers: Custom header values
  • Query Parameters: URL query string values
  • Request Body: Field values or regex patterns in JSON bodies

Route Management API

Creating Routes

Create a new routing rule with a unique name and configuration:

POST /api/v1/routes

Validation ensures:

  • Route name is unique and properly formatted
  • At least one matcher is configured (unless it's a default rule)
  • Target URL is valid
  • Priority is between 0 and 1000
  • Only one default route exists per configuration
Updating Routes - Rename Semantics

The update operation supports renaming routes through its dual-parameter design:

PUT /api/v1/routes/{name}

Important: Rename Safety

  • The {name} path parameter specifies the current route name to identify which route to update
  • The name field in the request body specifies the new route name
  • If the request body name differs from the path name, the route is renamed
  • If they match, the route is updated without renaming

Example: Renaming a route from "api-v1" to "api-v2":

curl -X PUT /api/v1/routes/api-v1 \
  -H "Content-Type: application/json" \
  -d '{
    "name": "api-v2",
    "target_url": "http://backend:8080",
    "matchers": [...],
    "priority": 10
  }'

Example: Updating a route without renaming:

curl -X PUT /api/v1/routes/api-v1 \
  -H "Content-Type: application/json" \
  -d '{
    "name": "api-v1",
    "target_url": "http://backend:9000",
    "matchers": [...],
    "priority": 20
  }'
Querying Routes

Retrieve a specific routing rule:

GET /api/v1/routes/{name}

List all active routes with pagination:

GET /api/v1/routes?offset=0&limit=50
Deleting Routes

Remove a routing rule:

DELETE /api/v1/routes/{name}

Safety Considerations

Atomic Updates

Route updates are atomic at the database level, but clients should be aware that:

  • In-flight requests may use old route configurations during updates
  • Route priority changes take effect immediately for new requests
  • Renaming a route invalidates any cached references to the old name
System Routes

Certain routes are protected and cannot be modified or deleted. These include:

  • Cube internal routes and audit routes
  • Any route marked as a system route in the configuration

Attempts to create, update, or delete system routes will return ErrSystemRouteProtected.

Validation Rules

Route names must:

  • Be non-empty
  • Contain only alphanumeric characters, hyphens (-), and underscores (_)
  • Be unique within the routing configuration

All matchers must define valid patterns. Regex patterns are validated at route creation/update time.

Conflicts and Constraints
  • Duplicate Names: Creating or renaming to an existing route name will fail
  • Multiple Defaults: Only one default route is allowed
  • Disabled Routes: Routes with enabled: false are excluded from matching but still stored
  • Invalid Patterns: Malformed regex in matchers will be rejected with ErrInvalidRegex
Request Forwarding

After a route is matched:

  1. The matched route's target URL is selected
  2. If StripPrefix is configured, it's removed from the request path
  3. The request is forwarded to the target URL
  4. Response is returned to the client

Configuration Example

{
  "routes": [
    {
      "name": "api-v2",
      "target_url": "http://backend-v2:8080",
      "matchers": [
        {
          "condition": "path",
          "pattern": "^/api/v2/.*",
          "is_regex": true
        },
        {
          "condition": "method",
          "pattern": "GET|POST"
        }
      ],
      "priority": 100,
      "enabled": true
    },
    {
      "name": "api-v1",
      "target_url": "http://backend-v1:8080",
      "matchers": [
        {
          "condition": "path",
          "pattern": "^/api/v1/.*",
          "is_regex": true
        }
      ],
      "priority": 50,
      "enabled": true
    },
    {
      "name": "default",
      "target_url": "http://default-backend:8080",
      "matchers": [],
      "default_rule": true,
      "priority": 0
    }
  ],
  "default_url": "http://fallback:8080"
}

Client Implementation Tips

When Renaming Routes
  1. Always verify the current name before performing a rename operation
  2. Ensure unique new names by checking existing routes first
  3. Handle concurrent updates gracefully; check for ErrRouteConflict
  4. Update internal references if your client caches route names
Monitoring Route Changes
  • Subscribe to route update events if available
  • Reload route configurations periodically
  • Log rename operations for audit trails
Error Handling

Expect these common errors:

  • ErrRouteNotFound: Route doesn't exist (may occur if renamed elsewhere)
  • ErrRouteConflict: Name already exists
  • ErrInvalidRouteName: Name format is invalid
  • ErrSystemRouteProtected: Cannot modify protected routes
  • ErrMultipleDefaultRoutes: Only one default route allowed

Performance Considerations

  • Priority-based evaluation: Higher priority routes are checked first, so frequently matched routes should have higher priority
  • Regex performance: Complex regex patterns in matchers impact routing latency
  • Memory usage: Each route maintains a compiled matcher in memory; disable unused routes with enabled: false
  • Atomic updates: Route configuration updates are thread-safe but may cause brief lock contention on high-traffic systems

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidRouteName      = errors.New("invalid route name: must be alphanumeric with hyphens or underscores")
	ErrRouteNameRequired     = errors.New("route name is required")
	ErrInvalidURL            = errors.New("invalid target URL")
	ErrInvalidMatcher        = errors.New("invalid route matcher configuration")
	ErrInvalidRegex          = errors.New("invalid regex pattern in matcher")
	ErrRouteConflict         = errors.New("route conflicts with existing route")
	ErrSystemRouteProtected  = errors.New("system route cannot be modified or deleted")
	ErrRouteNotFound         = errors.New("route not found")
	ErrInvalidPriority       = errors.New("invalid priority: must be between 0 and 1000")
	ErrNoMatchers            = errors.New("route must have at least one matcher or be a default rule")
	ErrMultipleDefaultRoutes = errors.New("only one default route is allowed")
	ErrInvalidStripPrefix    = errors.New("strip_prefix must start with /")
)

Route validation and management errors.

View Source
var ErrNoMatchingRoute = errors.New("no matching route found")

ErrNoMatchingRoute indicates that no route matched the request.

Functions

func DetectConflict

func DetectConflict(newRoute *RouteRule, existingRoutes []RouteRule) error

DetectConflict checks if a new route conflicts with existing routes. This is a basic implementation that checks for exact name conflicts. More sophisticated conflict detection could check for overlapping matchers.

func IsSystemRoute

func IsSystemRoute(name string) bool

IsSystemRoute checks if a route is a protected system route.

func ValidateMatcher

func ValidateMatcher(matcher RouteMatcher) error

ValidateMatcher checks if a single route matcher is valid.

func ValidateMatchers

func ValidateMatchers(matchers []RouteMatcher) error

ValidateMatchers checks if route matchers are valid.

func ValidatePriority

func ValidatePriority(priority int) error

ValidatePriority checks if priority is within valid range.

func ValidateRoute

func ValidateRoute(route *RouteRule) error

ValidateRoute performs comprehensive validation on a route rule.

func ValidateRouteName

func ValidateRouteName(name string) error

ValidateRouteName checks if a route name is valid. Valid names contain only alphanumeric characters, hyphens, and underscores.

func ValidateURL

func ValidateURL(targetURL string) error

ValidateURL checks if a target URL is valid.

Types

type BodyFieldMatcher

type BodyFieldMatcher struct {
	Field   string
	Pattern string
	IsRegex bool
}

BodyFieldMatcher matches against a specific field in the request body (JSON).

func (*BodyFieldMatcher) Match

func (m *BodyFieldMatcher) Match(r *http.Request) bool

type BodyRegexMatcher

type BodyRegexMatcher struct {
	Pattern string
}

BodyRegexMatcher matches against the entire request body using regex.

func (*BodyRegexMatcher) Match

func (m *BodyRegexMatcher) Match(r *http.Request) bool

type CompositeMatcher

type CompositeMatcher struct {
	Matchers []Matcher
}

CompositeMatcher allows combining multiple matchers with AND logic.

func (*CompositeMatcher) Match

func (m *CompositeMatcher) Match(r *http.Request) bool

type Config

type Config struct {
	Routes     []RouteRule `json:"routes"`
	DefaultURL string      `json:"default_url,omitempty"` // Fallback if no default rule is defined
}

Config contains the routing configuration.

type HeaderMatcher

type HeaderMatcher struct {
	Field   string
	Pattern string
	IsRegex bool
}

HeaderMatcher matches against a specific header value.

func (*HeaderMatcher) Match

func (m *HeaderMatcher) Match(r *http.Request) bool

type Matcher

type Matcher interface {
	Match(r *http.Request) bool
}

Matcher defines the interface for request matching logic.

func CreateCompositeMatcher

func CreateCompositeMatcher(matchers []RouteMatcher) Matcher

CreateCompositeMatcher creates a composite matcher from multiple RouteMatcher configurations.

func CreateMatcher

func CreateMatcher(rm RouteMatcher) Matcher

CreateMatcher creates matchers from RouteMatcher configuration.

type MethodMatcher

type MethodMatcher struct {
	Pattern string
	IsRegex bool
}

MethodMatcher matches against the HTTP method.

func (*MethodMatcher) Match

func (m *MethodMatcher) Match(r *http.Request) bool

type PathMatcher

type PathMatcher struct {
	Pattern string
	IsRegex bool
}

PathMatcher matches against the request path.

func (*PathMatcher) Match

func (m *PathMatcher) Match(r *http.Request) bool

type QueryParamMatcher

type QueryParamMatcher struct {
	Field   string
	Pattern string
	IsRegex bool
}

QueryParamMatcher matches against a query parameter value.

func (*QueryParamMatcher) Match

func (m *QueryParamMatcher) Match(r *http.Request) bool

type RouteCondition

type RouteCondition string

RouteCondition defines the type of condition to match.

const (
	RouteConditionPath       RouteCondition = "path"
	RouteConditionMethod     RouteCondition = "method"
	RouteConditionHeader     RouteCondition = "header"
	RouteConditionBodyField  RouteCondition = "body_field"
	RouteConditionBodyRegex  RouteCondition = "body_regex"
	RouteConditionQueryParam RouteCondition = "query_param"
)

type RouteMatcher

type RouteMatcher struct {
	Condition RouteCondition `json:"condition"`
	Field     string         `json:"field,omitempty"`    // For headers, query params, or body fields
	Pattern   string         `json:"pattern"`            // Pattern to match (can be regex or exact)
	IsRegex   bool           `json:"is_regex,omitempty"` // Whether pattern is a regex
}

RouteMatcher defines a single matching condition (for configuration).

type RouteRule

type RouteRule struct {
	Name        string         `json:"name"`
	TargetURL   string         `json:"target_url"`
	Matchers    []RouteMatcher `json:"matchers"`               // All matchers must match (AND logic)
	Priority    int            `json:"priority"`               // Higher priority rules are checked first
	DefaultRule bool           `json:"default_rule"`           // If true, this rule matches when no others do
	StripPrefix string         `json:"strip_prefix,omitempty"` // Prefix to strip from the path
	Enabled     *bool          `json:"enabled,omitempty"`      // If false, route is skipped. Defaults to true if not set.
	EventType   string         `json:"event_type,omitempty"`   // Event type for audit logging
	ATLS        bool           `json:"atls,omitempty"`         // Whether aTLS is expected for this route
	// contains filtered or unexported fields
}

RouteRule defines a complete routing rule.

type RouteRules

type RouteRules []RouteRule

RouteRules implements sort.Interface for []RouteRule based on Priority field. Routes are sorted in descending order of priority (higher priority first).

func (RouteRules) Len

func (r RouteRules) Len() int

func (RouteRules) Less

func (r RouteRules) Less(i, j int) bool

func (RouteRules) Swap

func (r RouteRules) Swap(i, j int)

type Router

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

func New

func New(config Config) *Router

func (*Router) DetermineTarget

func (r *Router) DetermineTarget(req *http.Request) (*RouteRule, error)

func (*Router) UpdateRoutes

func (r *Router) UpdateRoutes(newRoutes []RouteRule)

UpdateRoutes atomically replaces the current routes with new ones. This allows runtime modification of routes without restart.

Jump to

Keyboard shortcuts

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