Skip to main content

Overview

The fallback middleware provides fallback responses when the primary handler fails, enabling graceful degradation of services. Use it when you need:
  • Graceful degradation
  • Default responses on failure
  • Service resilience

Installation

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

Quick Start

app := mizu.New()

// Return cached data on error
app.Use(fallback.New(func(c *mizu.Ctx) error {
    return c.JSON(200, cachedResponse)
}))

Configuration

Options

OptionTypeDefaultDescription
Handlermizu.HandlerRequiredFallback handler
OnErrorfunc(error) boolAll errorsWhich errors trigger fallback
OnStatus[]int[]Status codes that trigger fallback

Examples

Basic Fallback

app.Use(fallback.New(func(c *mizu.Ctx) error {
    return c.JSON(200, map[string]string{
        "message": "Service temporarily unavailable",
        "status":  "degraded",
    })
}))

On Specific Errors

app.Use(fallback.WithOptions(fallback.Options{
    Handler: fallbackHandler,
    OnError: func(err error) bool {
        return errors.Is(err, ErrDatabaseUnavailable)
    },
}))

On Status Codes

app.Use(fallback.WithOptions(fallback.Options{
    Handler:  fallbackHandler,
    OnStatus: []int{500, 502, 503, 504},
}))

Cached Response

var cachedData atomic.Value

// Update cache periodically
go func() {
    for {
        data := fetchData()
        cachedData.Store(data)
        time.Sleep(time.Minute)
    }
}()

app.Use(fallback.New(func(c *mizu.Ctx) error {
    return c.JSON(200, cachedData.Load())
}))

API Reference

Functions

// New creates fallback middleware
func New(handler mizu.Handler) mizu.Middleware

// WithOptions creates with configuration
func WithOptions(opts Options) mizu.Middleware

Technical Details

Implementation Architecture

The fallback middleware operates using a wrapper pattern that intercepts errors from downstream handlers:
  1. Error Interception: The middleware wraps the next handler in the chain and catches any returned errors
  2. Panic Recovery: When CatchPanic is enabled, it uses Go’s defer/recover mechanism to catch panics and convert them to errors
  3. Response Capture: For status code-based fallbacks (like NotFound), it uses a custom responseCapture type that wraps http.ResponseWriter to intercept status codes
  4. Handler Delegation: Based on the configuration, it delegates to the appropriate fallback handler

Key Components

  • Options: Configuration structure that defines when and how to trigger fallback responses
  • responseCapture: Internal type that captures HTTP response status codes before they’re written
  • panicError: Custom error type that wraps panic values, converting non-error panics into error types

Execution Flow

Request → Middleware → [Optional Panic Recovery] → Next Handler → Error Check → Fallback Handler (if needed) → Response

Error Handling Chain

The middleware provides multiple fallback strategies that can be composed:
  1. New(): Basic error handler with custom function
  2. Default(): Simple text response fallback
  3. JSON(): Structured JSON error responses
  4. Redirect(): Redirect-based error handling
  5. Chain(): Sequential fallback handlers with conditional logic
  6. NotFound(): Status code-specific handling for 404s
  7. ForStatus(): Generic status code-specific handling

Best Practices

  • Keep fallback responses lightweight
  • Log when fallback is triggered
  • Monitor fallback rate
  • Use cached data when possible

Testing

The fallback middleware includes comprehensive test coverage for various scenarios:
Test CaseDescriptionExpected Behavior
TestNewBasic fallback middleware creationReturns custom error message when handler errors
TestWithOptions_CatchPanicPanic recovery with custom handlerCatches panic and returns custom response with 500 status
TestWithOptions_DefaultMessageDefault message without custom handlerReturns configured default message on error
TestWithOptions_NoErrorSuccessful request handlingPasses through successful responses without triggering fallback
TestDefaultDefault text fallbackReturns simple text message on error
TestJSONJSON error responsesReturns JSON-formatted error with proper content type
TestRedirectRedirect on errorRedirects to specified URL with correct status code
TestChainChained fallback handlersTries handlers in order, uses first that handles the error
TestChain_NoHandlerMatchesChain with no matchesReturns default “An error occurred” message
TestPanicWithErrorPanic with error typeCatches error panic and formats message correctly
TestPanicWithNonErrorPanic with non-error typeConverts non-error panic to “panic occurred” message
TestPanicWithDefaultHandlerPanic without custom handlerUses default message when no custom handler provided
TestNotFound404 not found handlingTriggers custom handler on 404 status
TestForStatusStatus code-specific handlingCreates middleware for specific status codes
TestWithOptions_DefaultsUsedDefault configuration valuesUses “An error occurred” when no config provided
TestResponseCapture_WriteHeaderResponse status capturingCaptures first status code, ignores subsequent writes
TestResponseCapture_WriteResponse write interceptionSets status to 200 on first write if not set
TestPanicError_ErrorMethodPanic error type behaviorCorrectly formats error messages for different panic types