> ## 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.

# ETag

> ETag generation middleware for HTTP caching and conditional requests.

## 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

```go theme={null}
import "github.com/go-mizu/mizu/middlewares/etag"
```

## Quick Start

```go theme={null}
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

### Strong ETags (Default)

```go theme={null}
app.Use(etag.New())
// Generates: ETag: "abc123def456"
```

### Weak ETags

```go theme={null}
app.Use(etag.Weak())
// Generates: ETag: W/"abc123def456"
```

### Custom Hash Function

```go theme={null}
app.Use(etag.WithOptions(etag.Options{
    HashFunc: func(body []byte) string {
        h := sha256.Sum256(body)
        return hex.EncodeToString(h[:16])
    },
}))
```

## How It Works

1. Request comes in without `If-None-Match`
2. Response is generated with ETag header
3. Client caches response with ETag
4. Next request includes `If-None-Match: "etag-value"`
5. If content unchanged, returns 304 Not Modified
6. If changed, returns new response with new ETag

## API Reference

### Functions

```go theme={null}
// 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

## Strong vs Weak ETags

| 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.

### ETag Format

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       |

## Related Middlewares

* [cache](/middlewares/cache) - Cache-Control headers
* [lastmodified](/middlewares/lastmodified) - Last-Modified headers
* [compress](/middlewares/compress) - Response compression
