Start learning free

LESSON 126 OF 188 · BACKEND: SPEED

ETags and 304

Practice

The cache saves the server's work, but the shop still sends the whole product list every time, even to a browser that got the very same list a minute ago. An ETag fixes that: a short fingerprint of an answer, sent in a header next to it. The same content always gives the same ETag; change one price and it is completely different.

A browser that has a copy sends its ETag back in the If-None-Match header, meaning "send it only if it isn't this one". If the fingerprint still matches, the server answers 304 Not Modified with an empty body, and the browser shows its own copy. A few bytes travel instead of the whole list.

One place for every route: Flask calls a function under @app.after_request after every route, with the answer the route made, and sends whatever that function returns. For example, this one adds a header to every answer:

@app.after_request
def add_shop_name(response):
    response.headers["X-Shop"] = "AlgoShop"
    return response

Your code must give these answers, in this order. The 304s save the trip, not the query: the cache still does that job, so the count stays at 4.

GET /products  →  200  ETag: "538c402a363ca03547c50a62d27c5b53"  [all 8 products, Mug at 12]
GET /products  If-None-Match: "538c402a363ca03547c50a62d27c5b53"  →  304  ETag: "538c402a363ca03547c50a62d27c5b53"  (empty body)
PATCH /products/1  {"price": 13}  →  200  {"id": 1, "price": 13}  (no ETag)
GET /products  If-None-Match: "538c402a363ca03547c50a62d27c5b53"  →  200  ETag: "4f136b3d3752465e3477229b9909a345"  [all 8 products, Mug at 13]
GET /products  If-None-Match: "4f136b3d3752465e3477229b9909a345"  →  304  ETag: "4f136b3d3752465e3477229b9909a345"  (empty body)
GET /products/99  →  404  {"error": "Product not found"}  (no ETag)
GET /debug/queries  →  200  {"queries": 4}

Your task: below run_query, add an @app.after_request function add_etag(response). For a GET that answered 200, hash the answer's bytes with hashlib.md5 and send the hash as the ETag. If the browser's If-None-Match holds that same ETag, answer 304 with an empty body.


Assignment
Follow the Coding Tutorial to add ETags and 304 answers to the shop's successful GET requests.


Hint
response.get_data() gives the answer's bytes, .hexdigest() turns the hash into text, and response.set_etag(etag) writes the header in the quotes HTTP wants. Flask reads the browser's header into request.if_none_match, so you can test etag in request.if_none_match.


STEP 1 OF 8
    Ctrl + Enter to check