import hashlib
import json
def compute_etag(payload, weak=False):
body = json.dumps(payload, sort_keys=True, separators=(",", ":"))
digest = hashlib.sha256(body.encode("utf-8")).hexdigest()[:32]
tag = '"{}"'.format(digest)
return "W/" + tag if weak else tag
def parse_if_none_match(header_value):
if not header_value:
return set()
if header_value.strip() == "*":
return {"*"}
tags = set()
for raw in header_value.split(","):
candidate = raw.strip()
if candidate.startswith("W/"):
candidate = candidate[2:].strip()
if candidate:
tags.add(candidate)
return tags
def etag_matches(current_etag, header_value):
provided = parse_if_none_match(header_value)
if "*" in provided:
return True
normalized = current_etag[2:] if current_etag.startswith("W/") else current_etag
return normalized in provided
from functools import wraps
from flask import request, jsonify, Response
from etag import compute_etag, etag_matches
def conditional(max_age=60):
def decorator(view):
@wraps(view)
def wrapper(*args, **kwargs):
payload = view(*args, **kwargs)
current_etag = compute_etag(payload)
cache_control = "private, max-age={}".format(max_age)
if etag_matches(current_etag, request.headers.get("If-None-Match")):
not_modified = Response(status=304)
not_modified.headers["ETag"] = current_etag
not_modified.headers["Cache-Control"] = cache_control
return not_modified
response = jsonify(payload)
response.headers["ETag"] = current_etag
response.headers["Cache-Control"] = cache_control
response.headers["Vary"] = "Accept-Encoding"
return response
return wrapper
return decorator
from flask import Flask, abort
from conditional import conditional
app = Flask(__name__)
_ARTICLES = {
1: {"id": 1, "title": "Conditional GET", "updated_at": "2024-05-01T10:00:00Z"},
2: {"id": 2, "title": "ETags in Practice", "updated_at": "2024-05-03T18:30:00Z"},
}
def _load_article(article_id):
record = _ARTICLES.get(article_id)
if record is None:
abort(404)
return record
@app.route("/articles/<int:article_id>")
@conditional(max_age=120)
def get_article(article_id):
article = _load_article(article_id)
return {
"id": article["id"],
"title": article["title"],
"updated_at": article["updated_at"],
}
if __name__ == "__main__":
app.run(debug=True)
Conditional GET is an HTTP mechanism that lets a client skip re-downloading a resource it already has. The server sends an ETag (a validator that identifies a specific version of a representation); on the next request the client echoes it back in If-None-Match, and the server replies 304 Not Modified with an empty body when nothing changed. This saves bandwidth and time while keeping caches correct, since the validator is compared server-side rather than trusting a stale local copy.
In etag.py, compute_etag derives a stable, content-based validator. It serializes the payload with sorted keys so logically-equal dicts hash identically, then takes a truncated SHA-256 digest and wraps it in quotes as HTTP requires. The prefix distinguishes weak from strong tags; this implementation emits strong tags because the bytes are compared exactly. parse_if_none_match normalizes the header, splitting on commas and handling the * wildcard as well as the W/ weak marker, so comparison is robust against client formatting quirks.
In conditional.py, the conditional decorator wraps a view that returns a JSON-able object. make_etag produces the validator, then etag_matches checks the incoming If-None-Match set. On a match the decorator short-circuits with a bare 304 response — crucially still carrying the ETag and Cache-Control headers, since a 304 must repeat the caching validators. Otherwise it builds a normal 200 with the same ETag, so the client can revalidate next time. The body is only serialized once and reused.
In app.py, get_article is a plain view that fetches data and returns a dict; the decorator handles all the HTTP plumbing. The _load_article helper simulates a store whose updated_at feeds into the ETag, so edits naturally invalidate the cached version.
A key trade-off is cost: hashing the full body defeats the point if generating that body is expensive, so this pattern shines when serialization is cheap relative to network transfer. Last-Modified is an alternative validator with second-granularity and clock-skew pitfalls; ETags avoid those but require deterministic serialization. A common bug is forgetting to send Vary when the representation depends on headers like Accept-Encoding — omitting it can poison shared caches.
Related snips
payload = {
sub: user.id,
iss: 'https://auth.example.com',
aud: 'codesnips-api',
exp: 15.minutes.from_now.to_i,
iat: Time.now.to_i,
JWT issuance and verification without common footguns
export interface RetryOptions {
retries: number;
baseMs: number;
maxMs: number;
signal?: AbortSignal;
onRetry?: (attempt: number, delay: number, err: unknown) => void;
Exponential backoff with jitter for retries
module Api
module V1
class UsersController < BaseController
def show
user = User.includes(:profile).find(params[:id])
ETags for conditional requests and caching
require "csv"
class PeopleCsvStream
include Enumerable
HEADERS = %w[id full_name email signed_up_at plan].freeze
Resilient CSV Export as a Streamed Response
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
createdAt: String!
GraphQL API with Spring Boot
Rails.application.configure do
config.after_initialize do
Bullet.enable = true
Bullet.alert = false
Bullet.bullet_logger = true
Bullet.console = true
N+1 query detection with Bullet gem
Share this code
Here's the card — post it anywhere.