I am looking for a pattern that would allow me to better the UX for my users. I have a REST server running behind CloudFront being consumed from a plain React application on the frontend.
I'll simplify my example to illustrate my issue.
I have an endpoint called GET /posts/<id>
. When the browser asks for it, it comes with a max=age=180
which means it would get stored in the browser's cache and any subsequent call to GET /posts/<id>
will be served from the browser's cache for the duration of those 180 seconds, after which it will hit the CDN again to try and obtain a fresh copy.
That is okay for most users. I don't mind if updates to any post to delay up to 3 minutes before they're propagated to all the users. But there is one user who's the author of this post. That user can make changes to this post using PATCH /posts/<id>
. Let's call that user The Editor.
Here's a scenario I have right now:
GET /posts/5
PATCH /posts/5
.GET /posts/5
again -- but gets the stale copy from before the changes because 180 seconds haven't passed yet since the last GET
and the GET
issued after the PATCH
What I'd like the experience to be is:
GET /posts/5
PATCH /posts/5
.GET /posts/5
brings back a copy of the data with the changes the editor made with PATCH
right away, regardless of the 180 seconds of ttl
before a fresh copy can be obtained.GET /posts/5
I am using Axios, but I do not that SWR and React-Query support mutations. To my understanding this would allow the editor to declare a mutation for the object he just PATCH'ed
on the server, so that any subsequent calls he makes to GET /posts/5
will be served from there, until a fresher version can be obtained from the backend.
My questions are:
GET /posts/5
transparently?/GET posts/5
?TL;DR: Just append a harmless, gibberish querystring to the end of the request GET /posts/<id>?version=whatever
Good question. I must admit I don't know the full answer to this problem, but I want to share one well-known technique among frontend devs.
The technique is called cache busting. I'm not sure if this is the best practice, but I'm pretty sure it's widely practiced, since it's so straight-forward to understand.
Idea is simple. When you add a changed querystring to the end, you effectively change the URL, thus no cache is hit, you evade the whole cache problem.
So the detail steps to a solution for your particular use case would go like this:
GET /posts/<id>
for all usersversion
. You store this version
in localStorage so it can survive through page refresh.GET /posts/<id>?version=n
version
from n
to n+1
GET /posts/<id>?version=n+1
which is not cached, and would retrieve the up-to-date content.?version=n
querystring.I'm sure there're other solutions to this problem. I'm no expert of server config and HTTP headers so I'm not getting into that topic, but there must be something to look for.
As of pure frontend solution, there's Serivce Worker API for you to consider. The main point of this API is to enable devs to programmatically control cache strategies.
With this API, you could leave your current app code as-is, just install a service worker, then you could use the same cache busting technique in the background to fetch new content, or just delete the cache (using Cache API) when user edits, or even fake a response for the GET /posts/<id>
from the PATCH /posts/<id>
that user just send.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With