simonw
4 days ago
I've been wanting this from Cloudflare for years.
The classic problem here is if you do that thing where user agents that send "accept: text/html" get HTML, while user agents that don't get JSON or some other format.
This used to be impossible to deploy behind Cloudflare caching, because they ignored the Vary header on anything other than images - so you risked caching the JSON version and then serving it up to someone who was expecting HTML.
(Independent of the Cloudflare feature I ended up deciding never to use that pattern, because I prefer having URL that predictably returns HTML or JSON - I add a .json suffix to my apps to serve JSON instead.)
Joker_vD
4 days ago
Frankly, the supposed variability of the Accept header never really sat all that well with me; in practice I much prefer working with explicitly versioned endpoints — one of the most infuriating things is having to hardcode "Accept: text/x-myorgname-custom-json-blob-v4" because omitting it would produce "406 Not Acceptable". Bonus points if that's the only Accept header the service would ever accept in all of three years of it working before being decommissioned. Double bonus points if v5 would be introduced behind a separate URI anyway (and it, too, would require precisely "Accept: text/x-myorgname-custom-json-blob-v5" and nothing else).
yoavm
4 days ago
I always thought Accept (and Accept-Language) headers are quite neat. Surely I can try article.es.md first, get a 404, try article.en.md, get a 404, try article.es.txt, article.en.html and so on, until I find the thing I'm looking for. But Accept let's me say "I'll take any one of these, preferably in this order". This is especially useful now when agents are reading the web and they don't really need all of our HTML code - just the text.
If you're versioning the whole API though, I agree it's best behind a a /v2/ prefix.
cryptonector
3 days ago
REST is all about MIME types and Accept/Content-Type. So there goes REST.
TFA makes me think that your argument is stronger than I would have thought yesterday, though I still prefer to have Accept/Content-Type negotiation. Sibling's comment about negotiation is on-point.
Joker_vD
3 days ago
GET /article HTTP/1.1
Accept: text/markdown,text/x-markdown;q=0.9,text/plain;q=0.8,text/html;q=0.3
Accept-Language: es-AR,es-419,es;q=0.9,en;q=0.8,ja;q=0.7
HTTP/1.1 307 Found
Location: /en-US/article.html
Vary: Accept, Accept-Language
Cache-Control: public, max-age=31536000
ETag: whatever
GET /en-US/article.html HTTP/1.1
Accept: text/markdown,text/x-markdown;q=0.9,text/plain;q=0.8,text/html;q=0.3
Accept-Language: es-AR,es-419,es;q=0.9,en;q=0.8,ja;q=0.7
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Language: en-US
Content-Length: tl;dr
Cache-Control: public, max-age=31536000
ETag: whatever-deux
And I think there is Content-Location header as well?.. My point is, it's possible to divorce caching of the server's response that choses the best available representation from caching of the actual content, and if you can't send Vary with the first response, then "Cache-Control: private, max-age=0" will still probably won't kill your redirection-making server. Or there is the Negotiate/Alternates + 300 response code mechanism as well!cryptonector
3 days ago
Content-Location can't be used as the cache key though. But yes, you can use 3xx redirects and Location.
ramblerman
2 days ago
It sounds like you came up with a proper solution because cf didn’t support this silliness