Skip to main content

Overview

The rewrite middleware transforms URL paths internally without sending redirects to the client. The browser URL remains unchanged while the server processes a different path.

Installation

import "github.com/go-mizu/mizu/middlewares/rewrite"

Quick Start

app := mizu.New()

// Rewrite /api/v1/* to /api/*
app.Use(rewrite.New(rewrite.Prefix("/api/v1", "/api")))

Examples

Prefix Rewrite

// /old/* → /new/*
app.Use(rewrite.New(rewrite.Prefix("/old", "/new")))

Regex Rewrite

// /posts/123 → /articles/123
app.Use(rewrite.New(rewrite.Regex(`^/posts/(\d+)$`, "/articles/$1")))

Multiple Rules

app.Use(rewrite.New(
    rewrite.Prefix("/api/v1", "/api"),
    rewrite.Prefix("/legacy", "/current"),
    rewrite.Regex(`^/user/(\d+)$`, "/users/$1"),
))

Version Stripping

// Remove API version from path
app.Use(rewrite.New(
    rewrite.Regex(`^/v\d+/(.*)$`, "/$1"),
))

API Reference

func New(rules ...Rule) mizu.Middleware
func WithOptions(opts Options) mizu.Middleware
func Prefix(from, to string) Rule
func Regex(pattern, replacement string) Rule

Rule Type

type Rule struct {
    Match   string  // Pattern to match
    Rewrite string  // Replacement pattern
    Regex   bool    // Is Match a regex?
}

Rewrite vs Redirect

FeatureRewriteRedirect
Client seesOriginal URLNew URL
HTTP round tripNoYes
SEOHiddenVisible
Use caseInternal routingURL changes

Technical Details

Implementation Overview

The rewrite middleware operates by modifying the Request.URL.Path before the request reaches downstream handlers:
  1. Rule Compilation: Regex patterns are compiled once during middleware initialization to optimize performance
  2. Path Matching: Each incoming request’s path is evaluated against rules in order
  3. First Match Wins: Processing stops at the first matching rule
  4. Path Replacement: The request URL path is modified in-place

Rule Processing

Prefix Rules:
  • Uses strings.HasPrefix() for fast prefix matching
  • Strips the matched prefix and prepends the replacement
  • Example: /old/path with rule Prefix("/old", "/new") becomes /new/path
Regex Rules:
  • Compiled using Go’s regexp package during initialization
  • Supports capture groups ($1, $2, etc.) for dynamic replacements
  • Uses ReplaceAllString() for substitution
  • Example: /user/123/profile with pattern ^/user/(\d+)/profile$ and replacement /profiles/$1 becomes /profiles/123

Performance Characteristics

  • Initialization: O(n) where n is the number of regex rules
  • Per-Request: O(r) where r is the number of rules (worst case: no match)
  • Memory: Compiled regex patterns are cached
  • Early Exit: Processing stops after first match for efficiency

Internal State

The middleware maintains:
  • Compiled regex patterns in the Rule.re field
  • Original rule configuration in the Options struct
  • No request-specific state (thread-safe)

Best Practices

Rule Ordering

Place more specific rules before general ones:
app.Use(rewrite.New(
    rewrite.Regex(`^/api/v2/(.*)$`, "/v2/$1"),  // Specific
    rewrite.Prefix("/api", "/internal"),         // General
))

Performance Optimization

  • Minimize the number of regex rules when possible
  • Use prefix rules for simple path transformations
  • Test regex patterns for efficiency with large inputs

Security Considerations

  • Validate rewrite patterns to prevent unintended path access
  • Be cautious with user-controlled input in dynamic rules
  • Consider path traversal implications when rewriting paths

Testing

The rewrite middleware includes comprehensive test coverage for various scenarios:
Test CaseDescriptionExpected Behavior
TestNewBasic prefix rewriteRewrites /old/path to /new/path using prefix rule
TestWithOptions_RegexRegex pattern matchingMatches regex pattern with version number and resource path
TestWithOptions_MultipleRulesMultiple rule processingApplies first matching rule and stops processing
TestWithOptions_NoMatchPath without matching ruleLeaves path unchanged when no rules match
TestPrefixPrefix rule creationCreates rule with correct match, rewrite, and regex=false
TestRegexRegex rule creationCreates rule with pattern, replacement, and regex=true
TestWithOptions_RegexCaptureRegex capture groupsReplaces /user/123/profile with /profiles/123 using capture group