Skip to main content

Overview

The conditional middleware enables conditional execution of other middleware based on request properties. Use it when you need:
  • Skip middleware for certain routes
  • Apply middleware conditionally
  • Dynamic middleware chains

Installation

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

Quick Start

app := mizu.New()

// Only apply auth for /api routes
app.Use(conditional.If(
    func(c *mizu.Ctx) bool {
        return strings.HasPrefix(c.Request().URL.Path, "/api")
    },
    authMiddleware,
))

Examples

Path-Based

// Skip for health checks
app.Use(conditional.Unless(
    func(c *mizu.Ctx) bool {
        return c.Request().URL.Path == "/health"
    },
    rateLimitMiddleware,
))

Method-Based

// Only for mutations
app.Use(conditional.If(
    func(c *mizu.Ctx) bool {
        m := c.Request().Method
        return m == "POST" || m == "PUT" || m == "DELETE"
    },
    csrfMiddleware,
))

Header-Based

// Only for API requests
app.Use(conditional.If(
    func(c *mizu.Ctx) bool {
        return c.Request().Header.Get("Accept") == "application/json"
    },
    apiMiddleware,
))

Combine Conditions

app.Use(conditional.If(
    conditional.And(
        conditional.PathPrefix("/api"),
        conditional.Not(conditional.Path("/api/public")),
    ),
    authMiddleware,
))

API Reference

Functions

// If applies middleware when condition is true
func If(cond func(*mizu.Ctx) bool, m mizu.Middleware) mizu.Middleware

// Unless applies middleware when condition is false
func Unless(cond func(*mizu.Ctx) bool, m mizu.Middleware) mizu.Middleware

// Condition helpers
func Path(path string) func(*mizu.Ctx) bool
func PathPrefix(prefix string) func(*mizu.Ctx) bool
func Method(methods ...string) func(*mizu.Ctx) bool
func Header(key, value string) func(*mizu.Ctx) bool
func And(conditions ...func(*mizu.Ctx) bool) func(*mizu.Ctx) bool
func Or(conditions ...func(*mizu.Ctx) bool) func(*mizu.Ctx) bool
func Not(cond func(*mizu.Ctx) bool) func(*mizu.Ctx) bool

Technical Details

HTTP Conditional Request Processing

The conditional middleware implements HTTP conditional request handling as per RFC 7232. It provides efficient caching mechanisms through ETags and Last-Modified headers. Core Components:
  1. Response Capture: The middleware intercepts the response using a custom responseCapture writer that buffers both the status code and body content before sending it to the client.
  2. ETag Generation: By default, ETags are generated using MD5 hashing of the response body. The middleware supports both strong and weak ETags:
    • Strong ETag: "hash-value"
    • Weak ETag: W/"hash-value"
  3. Last-Modified Handling: When a ModTimeFunc is provided, the middleware sets the Last-Modified header and processes If-Modified-Since conditional requests.
Request Flow:
  1. Check if request method is GET or HEAD (only these methods support conditional requests)
  2. Capture the response body and status code
  3. Generate ETag from response body (if enabled)
  4. Set Last-Modified header (if configured)
  5. Check If-None-Match header against ETag
  6. Check If-Modified-Since header against modification time
  7. Return 304 Not Modified if conditions match, or send full response
Performance Considerations:
  • The middleware buffers the entire response body for ETag generation
  • MD5 hashing is used for ETag (not for security, just content fingerprinting)
  • Only processes 2xx status codes to avoid caching errors
  • Skips processing for non-GET/HEAD methods

Security Considerations

While MD5 is used for ETag generation, it’s important to note that this is not a security concern. ETags are content fingerprints for caching purposes, not cryptographic signatures. The MD5 algorithm is perfectly suitable for this use case.

Best Practices

  • Use clear condition names
  • Keep conditions simple
  • Document conditional behavior
  • Test edge cases
  • Consider response size when buffering for ETag generation
  • Use weak ETags for frequently changing content
  • Combine ETag and Last-Modified for optimal caching
  • Provide custom ETagFunc for better performance with large responses

Testing

The conditional middleware includes comprehensive test coverage for various scenarios:
Test CaseDescriptionExpected Behavior
TestNewBasic middleware initialization with defaultsETag header should be present in response
TestIfNoneMatch_NotModifiedRequest with matching If-None-Match headerReturns 304 Not Modified status
TestIfNoneMatch_ModifiedRequest with non-matching If-None-Match (content changed)Returns 200 OK with new content
TestWithOptions_WeakETagWeak ETag generation enabledETag header starts with β€œW/” prefix
TestWithOptions_LastModifiedLast-Modified header with custom ModTimeFuncLast-Modified header present in response
TestIfModifiedSinceRequest with If-Modified-Since matching modification timeReturns 304 Not Modified status
TestSkipNonGETPOST request processingNo ETag header for non-GET/HEAD methods
TestETagOnlyETag-only mode without Last-ModifiedOnly ETag header present
TestLastModifiedOnlyLast-Modified only mode without ETagOnly Last-Modified header present
TestWithModTimeCombined ETag and Last-ModifiedBoth headers present in response
TestCustomETagFuncCustom ETag generation functionUses custom ETag value instead of MD5 hash