Live data from Hacker News

ETag and HTTP Caching

rednafi.com

31–40 of 92 posts

Re: ETag and HTTP Caching

#31
post #29
post #26

Earlier quoted context omitted.

Which article would you ask Bob to read to learn the right way to do it?

Have to admit I've never used this code, and didn't know what it was about. Quickly read up about it. So ETag is a hash of the resource. You must provide it with requests that modify the resource. If your hash doesn't match the server hash, then 412 Precondition Failed is returned? https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/412 https://www.rfc-editor.org/rfc/rfc9110#status.412

You can provide all sorts of conditions using HTTP headers such as "If-Match", "If-None-Match", "If-Modified-Since", "If-Range", etc. The server can chose an HTTP code to indicate some sort of cache invalidation signal.

304 means "you're good, your cached version satisfies the conditions"

412 means "you're not good, your cached version does not satisfy the conditions"

412 usually applies to modifications, but it could be for reading too, in the case of ranged requests (getting a specific range of bytes from a large representation). See the "Range" header.

These are all interconected. The headers, the codes, etc. They are very useful for caching and can save a lot of bandwidth. Browsers and CDNs use them extensively. Server-to-server communcation could use them as well, but I haven't seen popular implementations (let's say, a web framework that provides abstraction over these mechanisms).

Re: ETag and HTTP Caching

#32
post #25

This is nice. It reminds of how miserable my life is. — Which HTTP code I should return for my API? I already used 404, 403, but I need another one. Damn, HTTP is so old and it makes no sense. — You can't use HTTP codes like that Bob, they're not a free choice. They're for the protocol, not for your app. — Let's look at the list. Hm... "412 Precondition Failed". Hey, it sounds nice. It fits to my use case. I'm gonna…

My coworkers insisted on always returning 200 and having the status code in JSON.

At least at that point it’s clearly not HTTP anymore, and it’s better than pretending to be compliant like your Bob. But something dies inside me whenever I have to work with it.

Re: ETag and HTTP Caching

#33
post #31
post #29

Earlier quoted context omitted.

Have to admit I've never used this code, and didn't know what it was about. Quickly read up about it. So ETag is a hash of the resource. You must provide it with requests that modify the resource. If your hash doesn't match the server hash, then 412 Precondition Failed is returned? https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/412 https://www.rfc-editor.org/rfc/rfc9110#status.412

You can provide all sorts of conditions using HTTP headers such as "If-Match", "If-None-Match", "If-Modified-Since", "If-Range", etc. The server can chose an HTTP code to indicate some sort of cache invalidation signal. 304 means "you're good, your cached version satisfies the conditions" 412 means "you're not good, your cached version does not satisfy the conditions" 412 usually applies to modifications, but it coul…

Also, other popular HTTP codes have cache implications.

For example, 404 implies "No indication is given of whether the condition is temporary or permanent". Cache invalidation headers don't apply to this code because a 404 means there's something about the _resource_ and not only the _representation_ that could not be found. That client cannot cache the 404 result, not even for a fraction of a second.

404's brother 410 implies "This condition is expected to be considered permanent.". A client that gets a 410 can cache that result, never needing to reach the server again. It means it's gone forever. That client can decide to never look up that URI again.

Very often, "400 Bad Request" is the best HTTP you can use if you are not sure what to use. Then, describe what the error means using other HTTP components and/or the response body.

HTTP can be very simple. GET (ask for a representation) and POST (send a representation) as methods only. 200 (success), 400 (client error) and 500 (server error) as response codes only. It's the best way to start, then move to more elaborate protocol features as you learn.

Re: ETag and HTTP Caching

#34
post #25

This is nice. It reminds of how miserable my life is. — Which HTTP code I should return for my API? I already used 404, 403, but I need another one. Damn, HTTP is so old and it makes no sense. — You can't use HTTP codes like that Bob, they're not a free choice. They're for the protocol, not for your app. — Let's look at the list. Hm... "412 Precondition Failed". Hey, it sounds nice. It fits to my use case. I'm gonna…

My coworkers insisted on always returning 200 and having the status code in JSON. At least at that point it’s clearly not HTTP anymore, and it’s better than pretending to be compliant like your Bob. But something dies inside me whenever I have to work with it.

That's exactly what SOAP and GraphQL do, they always return 200

Re: ETag and HTTP Caching

#35
I recently implemented this, great write-up. Regarding the hashing function, I’m curious about opinions. In my implementation I went for a cheap but weak cryptographic hash at first. Then I got worried that some auditor would flag it and time would be wasted convincing them to change their mind. But then I stumbled upon FNV [1], a non-cryptographic hash and part of Go’s standard library and went for it. Any thoughts?

[1]: https://en.m.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93...

Re: ETag and HTTP Caching

#36
post #25

This is nice. It reminds of how miserable my life is. — Which HTTP code I should return for my API? I already used 404, 403, but I need another one. Damn, HTTP is so old and it makes no sense. — You can't use HTTP codes like that Bob, they're not a free choice. They're for the protocol, not for your app. — Let's look at the list. Hm... "412 Precondition Failed". Hey, it sounds nice. It fits to my use case. I'm gonna…

My coworkers insisted on always returning 200 and having the status code in JSON. At least at that point it’s clearly not HTTP anymore, and it’s better than pretending to be compliant like your Bob. But something dies inside me whenever I have to work with it.

I'd say returning 200 for all successes is reasonable if the responses are simple.

Returning 200 for an error makes no sense. Having 400s and 500s is the simplest way to have observability over protocol behavior (think logs, error rates, etc). If you use all 200s, you'd have to re-implement observability by yourself, so you lose simplicity that you gained by ignoring those statuses.

It's the same thing with caching stuff. You could implement those outside the protocol, but then you'd be writing your own protocol (trying to be smarter than decades of engineering efforts).

Re: ETag and HTTP Caching

#37
post #25

This is nice. It reminds of how miserable my life is. — Which HTTP code I should return for my API? I already used 404, 403, but I need another one. Damn, HTTP is so old and it makes no sense. — You can't use HTTP codes like that Bob, they're not a free choice. They're for the protocol, not for your app. — Let's look at the list. Hm... "412 Precondition Failed". Hey, it sounds nice. It fits to my use case. I'm gonna…

Ah, the eternal battle. Do you return an HTTP error code if the problem lies in the domain?

I think I've seen everything on that scale.

On one end: { status: 200, error: InsufficientFunds }

On the other: - "let's use 409, it perfectly fits our use case" + "but we don't have useful error codes for all the other domain errors."

Re: ETag and HTTP Caching

#38
post #25

This is nice. It reminds of how miserable my life is. — Which HTTP code I should return for my API? I already used 404, 403, but I need another one. Damn, HTTP is so old and it makes no sense. — You can't use HTTP codes like that Bob, they're not a free choice. They're for the protocol, not for your app. — Let's look at the list. Hm... "412 Precondition Failed". Hey, it sounds nice. It fits to my use case. I'm gonna…

Ah, the eternal battle. Do you return an HTTP error code if the problem lies in the domain? I think I've seen everything on that scale. On one end: { status: 200, error: InsufficientFunds } On the other: - "let's use 409, it perfectly fits our use case" + "but we don't have useful error codes for all the other domain errors."

Status 200 with "InsufficientFunds" can be correct.

Let's assume your resource is "/account/1234/withdraw-availability"

It's a hypothetical endpoint you can GET to know if you can withdraw money. You hit it, and the request is sucessful (the server understood and will inform you whether withdrawaw is available or not).

Let's assume your resource is "/account/1234/withdraw"

This other hypothetical endpoint you can POST a request for money withdraw. Returning 200 here means the server understood and processed your request, so a 200 that does not withdraw makes no sense.

The same endpoint could also return a success "201" accepted (the server understood the request, but it is not processed yet). In the body, there would be a link for "/withdrawaws/48957987593845983475/status", a resource specific to this future processing, which you can GET later (maybe 1ms later, within the same socket). This GET could also return a 200, saying that such withdrawaw was not possible (the server sucessfully understood the request and will inform you about the status of the withdrawaw).

For this modeling stuff, the Roy Fielding dissertation about REST is more enlightening than the spec. The spec is still needed though.

Re: ETag and HTTP Caching

#39
post #25

This is nice. It reminds of how miserable my life is. — Which HTTP code I should return for my API? I already used 404, 403, but I need another one. Damn, HTTP is so old and it makes no sense. — You can't use HTTP codes like that Bob, they're not a free choice. They're for the protocol, not for your app. — Let's look at the list. Hm... "412 Precondition Failed". Hey, it sounds nice. It fits to my use case. I'm gonna…

For the shortcoming of conveying errors strictly through HTTP status codes, consider: RFC-7807, Problem Details for HTTP APIs[0] From the introduction: HTTP [RFC7230] status codes are sometimes not sufficient to convey enough information about an error to be helpful. While humans behind Web browsers can be informed about the nature of the problem with an HTML [W3C.REC-html5-20141028] response body, non-human consumer…

Nice one, but seems to be replaced with https://datatracker.ietf.org/doc/html/rfc9457

Re: ETag and HTTP Caching

#40
post #25

This is nice. It reminds of how miserable my life is. — Which HTTP code I should return for my API? I already used 404, 403, but I need another one. Damn, HTTP is so old and it makes no sense. — You can't use HTTP codes like that Bob, they're not a free choice. They're for the protocol, not for your app. — Let's look at the list. Hm... "412 Precondition Failed". Hey, it sounds nice. It fits to my use case. I'm gonna…

To be fair, to me HTTP looks like:

- The first line of an HTTP request has its own format (space-separated-ish), and mixes method and URL path.

- The URL path in that first line has its own format and weird escaping, and mixes one path with zero-or-more key value pairs.

- The headers have their own format.

- The body has its own format.

Most (all?) HTTP libraries for clients and servers abstract all that mess away into a neat object that could be easily represented in JSON (or bencode if you want something simple-ish while supporting binary data), but it's like using a nice program while knowing it's written in C[1].

Of course, JSON has its own problems, but in that case at least we only need to deal with the problems of one format that supports with proper nesting, not 4 different weird formats masquerading as one.

[1]: Disclaimer, I don't like Rust, so don't take this as a RIIR thing.

EDIT: To be clear, I don't agree with how Bob misuses HTTP in your example. I just find it sad that we're locked into this weirdly complex protocol.

Post reply on HN