Documentation Index
Fetch the complete documentation index at: https://docs.go-mizu.dev/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The etag middleware automatically generates ETag headers for responses, enabling efficient HTTP caching with conditional requests. When a client sends a matching If-None-Match header, it returns 304 Not Modified.
Use it when you need:
- Bandwidth optimization through caching
- Conditional GET requests
- Cache validation
Installation
import "github.com/go-mizu/mizu/middlewares/etag"
Quick Start
app := mizu.New()
// Enable ETag generation
app.Use(etag.New())
app.Get("/api/data", func(c *mizu.Ctx) error {
return c.JSON(200, data)
})
Configuration
Options
| Option | Type | Default | Description |
|---|
Weak | bool | false | Generate weak ETags |
HashFunc | func([]byte) string | MD5 hash | Custom hash function |
Examples
app.Use(etag.New())
// Generates: ETag: "abc123def456"
app.Use(etag.Weak())
// Generates: ETag: W/"abc123def456"
Custom Hash Function
app.Use(etag.WithOptions(etag.Options{
HashFunc: func(body []byte) string {
h := sha256.Sum256(body)
return hex.EncodeToString(h[:16])
},
}))
How It Works
- Request comes in without
If-None-Match
- Response is generated with ETag header
- Client caches response with ETag
- Next request includes
If-None-Match: "etag-value"
- If content unchanged, returns 304 Not Modified
- If changed, returns new response with new ETag
API Reference
Functions
// New creates ETag middleware with defaults
func New() mizu.Middleware
// Weak creates middleware generating weak ETags
func Weak() mizu.Middleware
// WithOptions creates middleware with configuration
func WithOptions(opts Options) mizu.Middleware
Behavior
- Only generates ETags for GET and HEAD requests
- Skips error responses (4xx, 5xx)
- Returns 304 Not Modified for matching ETags
- Supports wildcard
If-None-Match: *
- Same content always produces same ETag
| Type | Format | Use Case |
|---|
| Strong | "abc123" | Byte-for-byte identical |
| Weak | W/"abc123" | Semantically equivalent |
Technical Details
The ETag middleware implementation uses a buffered writer approach to intercept and process responses:
Response Buffering
The middleware buffers the entire response body using a custom bufferedWriter that wraps the original http.ResponseWriter. This allows the middleware to:
- Calculate the hash of the complete response body
- Determine the final status code
- Conditionally return 304 Not Modified before sending the full response
Hash Generation
By default, the middleware uses CRC32 (IEEE polynomial) for hash generation, which provides:
- Fast computation suitable for HTTP caching
- Sufficient uniqueness for cache validation
- Low memory overhead
The hash function can be customized via HashFunc option to use alternative algorithms like SHA256 for enhanced security or collision resistance.
ETags are formatted according to RFC 7232:
- Strong ETags:
"<hash>" - Indicates byte-for-byte identical content
- Weak ETags:
W/"<hash>" - Indicates semantically equivalent content
Conditional Request Handling
The middleware checks the If-None-Match header from the client:
- If it matches the generated ETag, returns 304 Not Modified with the ETag header
- If it’s a wildcard (
*), always returns 304 Not Modified
- If no match, proceeds with the full response including the ETag header
Request Method Filtering
The middleware only processes GET and HEAD requests, as these are the only methods where conditional requests are applicable according to HTTP specifications.
Status Code Handling
ETags are only generated for successful responses (2xx status codes) with non-empty body content. Error responses (4xx, 5xx) are not cached and do not receive ETag headers.
Best Practices
- Use strong ETags for static files
- Use weak ETags for dynamic content that may vary slightly
- Combine with Cache-Control for full caching strategy
- Place after compression middleware
Testing
The middleware includes comprehensive test coverage for all functionality:
| Test Case | Description | Expected Behavior |
|---|
TestNew/generates_ETag | Basic ETag generation for GET request | Returns 200 OK with quoted ETag header |
TestNew/returns_304_for_matching_If-None-Match | Client sends matching If-None-Match header | Returns 304 Not Modified |
TestNew/returns_200_for_non-matching_If-None-Match | Client sends non-matching If-None-Match | Returns 200 OK with full response |
TestNew/wildcard_If-None-Match | Client sends If-None-Match: * | Returns 304 Not Modified |
TestWeak | Weak ETag generation | ETag header starts with W/" |
TestWithOptions_CustomHash | Custom hash function provided | Uses custom hash in ETag |
TestNew_SkipsNonGetHead | POST request made | No ETag header generated |
TestNew_SkipsErrorResponses | 500 error response | No ETag header generated |
TestNew_ConsistentETag | Same content returned twice | Both responses have identical ETags |
TestNew_DifferentContent | Different content returned | Different ETags generated |
TestNew_HEAD | HEAD request made | Processes request without errors |