Next.js Discord

Discord Forum

Optimizing External API Calls in Next.js with ISR and graphql-request

Answered
Ojos Azules posted this in #help-forum
Open in Discord
Ojos AzulesOP
I’m working on a Next.js application where I’m using Incremental Static Regeneration (ISR) to improve performance. However, I’m noticing a lot of external API hits, which is affecting the efficiency of my application. Here’s a breakdown of the current setup:

Header: Makes a global GraphQL call (external API).

Body: Makes a page-specific GraphQL call (external API).

Generate: Fetches metadata from an external API.

Footer: Makes another global GraphQL call (external API).

I’m using graphql-request for my GraphQL queries, so I can’t leverage Next.js’s built-in fetch caching. I’m looking for ways to use Next.js caching mechanisms to reduce the number of external API hits without switching to fetch.

Could you suggest strategies or best practices to cache these external API calls effectively while still using graphql-request? Any insights or examples would be greatly appreciated!
Answered by B33fb0n3
it looks like you are reusing your functions to get specific data, but nextjs does not dedupe the requests by default. You can wrap your unstable cache functions inside a React.cache(() => { your code here }) to dedupe your requests. Btw, you might want to set your revalidate to some value
View full answer

7 Replies

Ojos AzulesOP
@B33fb0n3 Thanks for the reply. I did go to the documentation, and I think to use the use cache option I have to turn on the experimental flag through the next config.
so i used unstable_cache as well.

I'm using generateStaticParams as in the v15 app router, and
const DynamicPage = async (props: { params: PagePropsTypes }) => {
  const { slug } = await props.params
  const cacheKey = `${slug ? slug.join('/') : 'home'}`
 
  const pageUris =
    (await sdk.GetPageUris()).pages?.nodes?.map((node) =>
      normalizeUri(node!.uri!)
    ) ?? []

  // disable cache for dev
  const query = (await unstable_cache(
    async () => await sdk.GetPage({ uri }),
    [cacheKey],
    {
      tags: [cacheKey],
      revalidate,
    }
  )()) as DeepRequired<GetPageQuery>

  if (!query.page) return notFound()


and on generate metadata as well with the same key in the cache
export async function generateMetadata(props: { params: PagePropsTypes }) {
  const { slug } = await props.params
  const uri = slug ? `/${slug.join('/')}` : '/'

  const cacheKey = `${slug ? slug.join('/') : 'home'}`

  try {
    // disable cache for dev
    const query = (await unstable_cache(
      async () => await sdk.GetPage({ uri }),
      [cacheKey],
      {
        tags: [cacheKey],
        revalidate,
      }
    )()) as DeepRequired<GetPageQuery>

it shows cache has been updated too on Vercel dashboard
Image
but it always takes 3sec to navigate between page (ISR should be fast once cache)
and if I see a monitor of external api hit, it incerase like 5 number
@Ojos Azules <@301376057326567425> Thanks for the reply. I did go to the documentation, and I think to use the `use cache` option I have to turn on the experimental flag through the next config. so i used `unstable_cache ` as well. I'm using generateStaticParams as in the v15 app router, and const DynamicPage = async (props: { params: PagePropsTypes }) => { const { slug } = await props.params const cacheKey = `${slug ? slug.join('/') : 'home'}` const pageUris = (await sdk.GetPageUris()).pages?.nodes?.map((node) => normalizeUri(node!.uri!) ) ?? [] // disable cache for dev const query = (await unstable_cache( async () => await sdk.GetPage({ uri }), [cacheKey], { tags: [cacheKey], revalidate, } )()) as DeepRequired<GetPageQuery> if (!query.page) return notFound() and on generate metadata as well with the same key in the cache export async function generateMetadata(props: { params: PagePropsTypes }) { const { slug } = await props.params const uri = slug ? `/${slug.join('/')}` : '/' const cacheKey = `${slug ? slug.join('/') : 'home'}` try { // disable cache for dev const query = (await unstable_cache( async () => await sdk.GetPage({ uri }), [cacheKey], { tags: [cacheKey], revalidate, } )()) as DeepRequired<GetPageQuery> it shows cache has been updated too on Vercel dashboard Image but it always takes 3sec to navigate between page (ISR should be fast once cache) and if I see a monitor of external api hit, it incerase like 5 number
it looks like you are reusing your functions to get specific data, but nextjs does not dedupe the requests by default. You can wrap your unstable cache functions inside a React.cache(() => { your code here }) to dedupe your requests. Btw, you might want to set your revalidate to some value
Answer
@Ojos Azules solved?
@B33fb0n3 <@634763003316928515> solved?
Ojos AzulesOP
yes, solved thank you, I didn't wrap with React.cache cause it was caching without, I think I miss cache for some endpoints, even on the above code. after this its been cache, I have revalidation of 10 minutes, i dont if it is too fast cause on extern api hit i see lots of number there .