How to correctly cache GET routes?
Unanswered
Russo-European Laika posted this in #help-forum
Russo-European LaikaOP
I pushed the code below to prod, but it seems that it caches forever. I would wait 2 mins, 5 mins, 10 mins, etc. and the same response was always returned and displayed on web pages. The data was also confirmed to have changed within those time frames.
28 Replies
Russo-European LaikaOP
My goal is to cache the response of this route for 90 seconds. I've tried adding custom
Cache-Control headers, as well as next.revalidate to the fetch() req. Thanks for any help 🙂@Russo-European Laika I pushed the code below to prod, but it seems that it caches forever. I would wait 2 mins, 5 mins, 10 mins, etc. and the same response was always returned and displayed on web pages. The data was also confirmed to have changed within those time frames.
Turkish Van
I might be wrong, but Your Route Handler shouldn't be even
Take a look here: https://nextjs.org/docs/app/building-your-application/routing/route-handlers#opting-out-of-caching
Are You sure You are not trying to
For example, there might be a function that You use to request data from that Router Handler which is being
cached, by default, at all. You are using the Request object with the GET method which automatically results into opting out of caching.Take a look here: https://nextjs.org/docs/app/building-your-application/routing/route-handlers#opting-out-of-caching
Are You sure You are not trying to
cache it at place of it being called?For example, there might be a function that You use to request data from that Router Handler which is being
cached.It might be helpful if You provided us with code snippet of You trying to request data from it inside of the component.
@Turkish Van I might be wrong, but Your Route Handler shouldn't be even `cached`, by default, at all. You are using the `Request` object with the `GET` method which automatically results into opting out of caching.
Take a look here: https://nextjs.org/docs/app/building-your-application/routing/route-handlers#opting-out-of-caching
Are You sure You are not trying to `cache` it at place of it being called?
For example, there might be a function that You use to request data from that Router Handler which is being `cached`.
Russo-European LaikaOP
Thanks, I will look into it further. I thought you could cache routes the same as caching pages.
This is how it's being using in the component (page)
@Russo-European Laika Thanks, I will look into it further. I thought you could cache routes the same as caching pages.
Turkish Van
You absolutely can!
But there are some edge cases which result into it opting out of
GET Route Handler are cached by default. Take a look at link provided above in case You would like to dive a bit deeper into it.But there are some edge cases which result into it opting out of
cache.Russo-European LaikaOP
Does the page need
force-dynamic at the top?And then I can cache the routes as needed?
@Russo-European Laika Click to see attachment
Turkish Van
Could You provide the code of the either
getClan or getRace function, the one that requests data from the Route Handler provided above?Russo-European LaikaOP
Just a simple service call, both are nearly identical
I guess I'm just confused as to where the caching should be added. Should
next.revalidate be in this fetch()?@Russo-European Laika Click to see attachment
Turkish Van
Is there a part where You are trying to generate static params for that page by using the
Try adding
generateStaticParams function?Try adding
export const revalidate = 90 at the top of the component, above ClanRace component.@Turkish Van Is there a part where You are trying to generate static params for that page by using the `generateStaticParams` function?
Try adding `export const revalidate = 90` at the top of the component, above `ClanRace` component.
Russo-European LaikaOP
using the generateStaticParams function?No, I don't use that at all.
My goal was to cache the
getClan route for 90 secs, and getRace for 30 secs. If I add revalidate = 90 to the top of the page, would that just cache all requests (the entire page) for 90 secs?getClan and getRace are used in other parts of my app, that's why@Russo-European Laika > using the generateStaticParams function?
No, I don't use that at all.
My goal was to cache the `getClan` route for 90 secs, and `getRace` for 30 secs. If I add `revalidate = 90` to the top of the page, would that just cache all requests (the entire page) for 90 secs?
Turkish Van
Oh, You could try adding these options to Your fetch
It might look like this:
Take a look here: https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#time-based-revalidation
fetch('https://...', { next: { revalidate: 3600 } }).It might look like this:
export async function getRace(tag, getRaceStats = false) {
return fetch(`${HOST}/api/clan/race?tag=${formatTag(tag)}&getRaceStats=${getRaceStats}`, { next: { revalidate: 90 } }).then(res => res.json());
}Take a look here: https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#time-based-revalidation
Russo-European LaikaOP
Thanks. Out of curiosity, what makes this different than what I had originally?
Where I added it to the top of the
GET routeThanks for your help btw 🙂
@Russo-European Laika Thanks. Out of curiosity, what makes this different than what I had originally?
Turkish Van
So the following explanation is based on my understanding, and since all of this is pretty new, I might be wrong.
Let's say You had a function
Then, let's say You also had a function
So the result of it would be:
- First call:
You call
- Second call:
You call
- Third call:
The same thing happens again.
So, the function
That is why I assumed there might be a function at the higher level that is caching the value which results in behaviour You are facing.
Let's say You had a function
getRandomNumber that gives You a random number each time You call it and is NEVER being cached.Then, let's say You also had a function
getRandomNumberCached that calls the getRandomNumber function and retrieves the number back to You. But, the getRandomNumberCached function IS cached.So the result of it would be:
- First call:
You call
getRandomNumberCached -> There is no cache -> it gets executed -> it calls a getRandomNumber function -> it receives the number, stores it in the cache and it gets back to You- Second call:
You call
getRandomNumberCached -> There is a cache -> it reads the cached value -> it returns the cached value to You- Third call:
The same thing happens again.
So, the function
getRandomNumberCached would retrieve the cached value as long as it does not get revalidated.That is why I assumed there might be a function at the higher level that is caching the value which results in behaviour You are facing.
I got it working now. One more quick question, is it possible to use both:
{
next: {
revalidate: 90,
tags: [`clan-${tag}`]
}
}My end goal is to cache the data for 90 seconds, but there is 1 scenario where the data needs to be up to date on request. I was trying to use
revalidateTag right before making that request, but doesn't seem to do it. Maybe I'm misunderstanding somethingSame issue with
revalidatePath. Maybe it's because the GET req has search params?Russo-European LaikaOP
My end goal would be something like this. Is this not possible?
@Russo-European Laika I got it working now. One more quick question, is it possible to use both:
js
{
next: {
revalidate: 90,
tags: [`clan-${tag}`]
}
}
Turkish Van
Yes, this should be possible.
Could You provide the code snippet of the function where the
Could You provide the code snippet of the function where the
revalidateTag function is being used?@Russo-European Laika My end goal would be something like this. Is this not possible?
Turkish Van
I might be wrong but, this wouldn't work since
It would work in case You passed to it the path to the page where the
revalidatePath function expects a page/layout path and not the api route path.It would work in case You passed to it the path to the page where the
getClan function is being used, that would revalidate the data retrieved by that function. But, since You said that those functions are being used in multiple places across the app, that might not be the best solution.