ETag Middleware
A lightweight, production‑ready ETag middleware for the Nexios ASGI framework.
It automatically:
- Computes and sets an
ETagheader for responses that don't already have one - Handles conditional
GET/HEADrequests viaIf-None-Matchand returns304 Not Modifiedwhen appropriate
Installation
bash
pip install nexios_contribQuick Start
python
from nexios import NexiosApp
import nexios_contrib.etag as etag
app = NexiosApp()
# Add the ETag middleware (defaults shown)
app.add_middleware(
etag.ETag(
weak=True, # Generate weak validators (W/ prefixes)
methods=("GET", "HEAD"), # Methods to apply to
override=False # Don't overwrite an existing ETag by default
)
)
@app.get("/")
async def home(request, response):
return {"message": "Hello with ETag!"}That's it! Responses to GET/HEAD will carry an ETag header. Clients sending If-None-Match will receive 304 when the ETag matches.
Configuration
Parameters
weak: bool = True
Use weak validators (e.g.W/"abc"). SetFalsefor strong validators when you know the body bytes are stable across platforms and encodings.methods: Iterable[str] = ("GET", "HEAD")
Limit conditional handling to idempotent methods. You can add others, but it's not typical.override: bool = False
IfTrue, overwrites anETagalready set by your handler.
How It Works
- If the handler doesn't set an
ETag, the middleware computes one from the response body and sets it - If the request includes
If-None-Matchand it matches the response'sETag(weak compare by default), the middleware converts the response into304 Not Modifiedand removes the body, per RFC 9110
Examples
Basic Usage
python
from nexios import NexiosApp
import nexios_contrib.etag as etag
app = NexiosApp()
app.add_middleware(etag.ETag())
@app.get("/api/data")
async def get_data(request, response):
# This response will automatically get an ETag
return {"data": "some content", "timestamp": "2024-01-01"}
# First request: Returns 200 with ETag: W/"abc123"
# Second request with If-None-Match: W/"abc123": Returns 304 Not ModifiedStrong ETags
python
app.add_middleware(
etag.ETag(
weak=False, # Use strong validators
methods=("GET", "HEAD")
)
)
@app.get("/api/file")
async def get_file(request, response):
# Strong ETag will be generated: "abc123" (no W/ prefix)
return {"file_content": "binary data"}Custom Methods
python
app.add_middleware(
etag.ETag(
methods=("GET", "HEAD", "POST"), # Include POST (not recommended)
override=True # Override existing ETags
)
)Best Practices
- Use for idempotent methods: Apply by default to
GETandHEAD. Avoid applying to mutating methods likePOST/PUTunless you know what you're doing - Consider response size: Streaming or extremely large bodies may benefit from precomputed/strong ETags at your handler or via a hash of a stable resource version
- Weak vs Strong: Use weak ETags (default) unless you need byte-for-byte identical responses
- Cache-friendly: ETags work great with HTTP caching - browsers and CDNs will use them automatically
Advanced Usage
Manual ETag Setting
python
@app.get("/api/custom")
async def custom_etag(request, response):
# Set your own ETag - middleware won't override by default
response.headers['ETag'] = 'W/"custom-etag-123"'
return {"data": "custom content"}Conditional Logic
python
@app.get("/api/conditional")
async def conditional_response(request, response):
# Check if client has current version
if_none_match = request.headers.get('If-None-Match')
current_etag = 'W/"version-456"'
if if_none_match == current_etag:
# Client has current version
response.status_code = 304
return None
# Return new content
response.headers['ETag'] = current_etag
return {"data": "updated content"}Notes
- When returning
304, the middleware ensures the body is empty and relies on the underlying response type to handle headers correctly - ETags are computed from the response body, so identical content will have identical ETags
- The middleware respects existing ETags unless
override=Trueis set
Performance Considerations
- ETag computation adds minimal overhead for small responses
- For large responses, consider pre-computing ETags based on resource versions
- ETags enable efficient caching, reducing server load for repeated requests
- Use with appropriate
Cache-Controlheaders for optimal caching behavior
Built with ❤️ by the @nexios-labs community.
