Skip to main content

Overview

The lastmodified middleware handles Last-Modified headers and If-Modified-Since conditional requests for efficient caching. Use it when you need:
  • Date-based caching
  • Conditional GET requests
  • Bandwidth optimization

Installation

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

Quick Start

app := mizu.New()

app.Use(lastmodified.New())

app.Get("/resource", func(c *mizu.Ctx) error {
    lastmodified.Set(c, resource.UpdatedAt)
    return c.JSON(200, resource)
})

Examples

Set Last-Modified

app.Get("/article/:id", func(c *mizu.Ctx) error {
    article := getArticle(c.Param("id"))
    lastmodified.Set(c, article.UpdatedAt)
    return c.JSON(200, article)
})

Auto Last-Modified

app.Use(lastmodified.Auto(func(c *mizu.Ctx) time.Time {
    // Return modification time based on request
    return getModTime(c.Request().URL.Path)
}))

Static Files

// Last-Modified is automatic for static files
app.Use(static.New("./public"))

How It Works

  1. Handler sets Last-Modified
  2. Client receives Last-Modified header
  3. Next request includes If-Modified-Since
  4. If not modified, returns 304 Not Modified
  5. If modified, returns full response

API Reference

Functions

// New creates Last-Modified middleware
func New() mizu.Middleware

// Set sets Last-Modified for response
func Set(c *mizu.Ctx, t time.Time)

// Auto creates auto Last-Modified middleware
func Auto(getModTime func(*mizu.Ctx) time.Time) mizu.Middleware

Technical Details

The middleware implementation follows HTTP RFC 7232 specifications for conditional requests:
  • Time Format: Uses HTTP-date format (RFC 5322) for Last-Modified headers
  • Time Comparison: Truncates to seconds precision for accurate comparison
  • Method Filtering: Only processes GET and HEAD requests
  • Header Parsing: Uses http.ParseTime which supports multiple date formats
  • 304 Response: Returns Not Modified when If-Modified-Since >= Last-Modified

Implementation Features

  • Options Configuration: Options struct allows customization with TimeFunc and SkipPaths
  • Path Skipping: Can skip specific paths using the SkipPaths option
  • Zero Time Handling: Skips middleware processing when time function returns zero time
  • UTC Normalization: Automatically converts times to UTC before setting headers

Helper Functions

  • Static(t time.Time): Creates middleware with a fixed modification time
  • Now(): Uses current time for each request (useful for development/testing)
  • StartupTime(): Uses application startup time (useful for versioned assets)
  • FromHeader(header string): Reads modification time from a custom request header

Best Practices

  • Use with ETag for robust caching
  • Set accurate modification times
  • Use for static and semi-static content
  • Combine with Cache-Control

Testing

The middleware includes comprehensive test coverage for various scenarios:
Test CaseDescriptionExpected Behavior
TestNewBasic middleware initializationSets Last-Modified header on response
TestIfModifiedSince_NotModifiedRequest with matching If-Modified-SinceReturns 304 Not Modified status
TestIfModifiedSince_ModifiedRequest with older If-Modified-SinceReturns 200 OK with full response
TestWithOptions_SkipPathsPath configured to be skippedNo Last-Modified header set
TestSkipPostMethodPOST request to endpointNo Last-Modified header (only GET/HEAD)
TestStaticStatic time middlewareReturns fixed Last-Modified time
TestNowCurrent time middlewareSets Last-Modified to current time
TestStartupTimeStartup time middlewareConsistent time across multiple requests
TestFromHeaderCustom header as time sourceReads and sets time from X-Resource-Modified
TestZeroTimeTime function returns zero valueNo Last-Modified header set
  • etag - ETag generation
  • cache - Cache-Control headers
  • static - Static files