Skip to content

Conditional Requests

DodaTech 2 min read

title: "Conditional Requests — ETag and If-Modified-Since for API Caching" description: "Conditional requests use ETag and If-Modified-Since headers to let clients check if cached content changed, returning 304 Not Modified to save bandwidth." date: 2026-06-28 lastmod: 2026-06-28 weight: 15 tags: [apis, caching] }

Conditional requests allow clients to validate cached responses using ETag (content hash) or If-Modified-Since (timestamp), returning 304 with no body if unchanged.

What You'll Learn

  • ETag generation and comparison
  • If-Modified-Since usage
  • Strong vs weak ETags

Why It Matters

Conditional requests reduce bandwidth to near zero for unchanged resources. Even if cache TTL expires, revalidation uses minimal overhead.

Conditional Request Flow

sequenceDiagram
    Client->>Cache: GET /resource
    Cache->>Origin: GET /resource (If-None-Match: "abc")
    Origin->>Origin: Check resource hash
    Origin-->>Cache: 304 Not Modified
    Cache-->>Client: 200 (from cache)

Code Examples

import hashlib

# Strong ETag from content hash
def compute_etag(data):
    return hashlib.sha256(json.dumps(data, sort_keys=True).encode()).hexdigest()

@app.route('/api/articles')
def get_articles():
    articles = db.get_articles()
    etag = compute_etag(articles)

    if request.headers.get('If-None-Match') == etag:
        return '', 304

    response = jsonify(articles)
    response.headers['ETag'] = etag
    response.headers['Cache-Control'] = 'public, max-age=300'
    return response

# Weak ETag for semantically equivalent content
def compute_weak_etag(data):
    # W/ prefix indicates weak ETag
    return f'W/"{hashlib.md5(str(data).encode()).hexdigest()}"'
// Conditional request with If-Modified-Since
app.get('/api/articles', (req, res) => {
  const articles = db.getArticles();
  const lastModified = getLastModified(articles);
  const etag = crypto.createHash('sha256').update(JSON.stringify(articles)).digest('hex');

  // Check If-Modified-Since
  const ifModifiedSince = req.headers['if-modified-since'];
  if (ifModifiedSince) {
    const clientTime = new Date(ifModifiedSince).getTime();
    if (lastModified.getTime() <= clientTime) {
      return res.status(304).end();
    }
  }

  // Check If-None-Match
  if (req.headers['if-none-match'] === etag) {
    return res.status(304).end();
  }

  res.set({
    'ETag': etag,
    'Last-Modified': lastModified.toUTCString(),
    'Cache-Control': 'public, max-age=300'
  });
  res.json(articles);
});

Common Mistakes

1. Weak ETag for Exact Comparisons

Weak ETags (W/"...") allow byte-level differences. Use strong ETags for exact content.

2. No ETag When Content Changes Frequently

ETags work even for frequently changing content — they just expire faster.

3. Using Last-Modified Without ETag

Use both. Last-Modified has second granularity; ETags catch sub-second changes.

4. Case-Sensitive ETag Comparison

Always use case-insensitive ETag comparison (except for quoted strings).

5. ETag Without Cache-Control

ETag validation only happens after cache expiry. Set appropriate TTL.

Practice Questions

  1. What is a strong vs weak ETag?
  2. How does If-None-Match work with ETag?
  3. What is the benefit of conditional requests?
  4. What happens when ETag matches?
  5. Should you use ETag, Last-Modified, or both?

Answers:

  1. Strong ETags compare byte-for-byte; weak ETags compare semantically.
  2. If ETag matches, server returns 304 with no body.
  3. Bandwidth reduction — only headers, no body, are transferred on validation.
  4. Server returns 304 Not Modified with empty body.
  5. Both. ETag for precision, Last-Modified for legacy clients.

Challenge: Implement ETag generation for a database-backed API. Use row version numbers or content hashes. Test with conditional requests and measure bandwidth savings.

FAQ

Can two different resources have the same ETag?

: Only if they have identical content. Strong ETags are unique per content.

Are conditional requests only for GET?

: No. Conditional requests work with HEAD, but not typically for mutations.

How long should an ETag be valid?

: ETags are valid until the content changes, regardless of cache TTL.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro