Next.js Discord

Discord Forum

Next 14 Caching my own api requests

Unanswered
Gray Flycatcher posted this in #help-forum
Open in Discord
Gray FlycatcherOP
Hi, I am trying to cache my api request located at /api/admin/getProducts, so that any time people request it it gives the cache, but when its tag is revalidated (when a product stock is updated) it revalidates it and runs the code within that api request again so that the returning response is the updated getProducts, I have tried this with revalidateTag and the tag stuff but it just isnt working.

38 Replies

West African Lion
@Gray Flycatcher i used that as well
what does your code looks like?
@alfonsus what does your code looks like?
Gray FlycatcherOP
ive got this admin page which gets the products, and displays them:
        async function fetchProducts() {
            try {
                const response = await (await fetch('/api/admin/getProducts', {next: { tags: ["testinggg"]}})).json();
                setProducts(response);
                setStartProducts(response);
            } catch (error) {
                console.error('Error fetching products:', error);
            } finally {
                setLoading(false);
            }
        }
        fetchProducts();
    }, []);


then the getProducts route is
import { NextResponse } from 'next/server';
import { GET as allProductSlugs } from '@/app/api/admin/getRecord/allProductSlugs/route';
import { GET as getProductById } from '@/app/api/admin/getRecord/[slug]/route';
import { GET as getPriceById } from '@/app/api/admin/getPrice/[priceId]/route';

export const revalidate = false;

export async function GET() {

    try {
        const allProductSlugsResponse = await allProductSlugs();
        const slugs = await allProductSlugsResponse.json();

        console.log("PRODUCTS")
        const enrichedProducts = await Promise.all(
            slugs.map(async (slug) => {
                try {
                    const productResponse = await getProductById(undefined, { params: { slug } });
                    const product = await productResponse.json();
                    const priceResponse = await getPriceById(undefined, { params: { priceId: product.stripePriceId } });
                    const price = await priceResponse.json();

                    return {
                        ...product,
                        price: price || null,
                    };
                } catch (error) {
                    console.error(`Failed to fetch data for slug ${slug}:`, error.message);
                    return null;
                }
            })
        );

        const validProducts = enrichedProducts.filter((product) => product !== null);

        return NextResponse.json(validProducts);
    } catch (error) {
        console.error('Error fetching all products:', error.message);
        return NextResponse.json({ error: 'Failed to fetch products.' }, { status: 500 });
    }
}
then in the update products api request, it does this revalidateTag('testinggg');, but nothing is revalidating.
@alfonsus Where is this code being used?
Gray FlycatcherOP
i’m calling the api request inside the code for a page, in a use effect
@Gray Flycatcher i’m calling the api request inside the code for a page, in a use effect
those tags wont work in client-side fetches
you have to put it in the server
@alfonsus those tags wont work in client-side fetches
Gray FlycatcherOP
ohh right so do I have to put it in a server side prop or smth
yeuh
you uhh
Gray FlycatcherOP
yeah in the next response
no not in the next response
Gray FlycatcherOP
i thought you can do like NextResponse.json(thing, {next:{tags:[…]}})
@alfonsus ~~you can put the tags here.~~
Gray FlycatcherOP
also wdym by here
@Gray Flycatcher js import { NextResponse } from 'next/server'; import { GET as allProductSlugs } from '@/app/api/admin/getRecord/allProductSlugs/route'; import { GET as getProductById } from '@/app/api/admin/getRecord/[slug]/route'; import { GET as getPriceById } from '@/app/api/admin/getPrice/[priceId]/route'; export const revalidate = false; export async function GET() { try { const allProductSlugsResponse = await allProductSlugs(); const slugs = await allProductSlugsResponse.json(); console.log("PRODUCTS") const enrichedProducts = await Promise.all( slugs.map(async (slug) => { try { const productResponse = await getProductById(undefined, { params: { slug } }); const product = await productResponse.json(); const priceResponse = await getPriceById(undefined, { params: { priceId: product.stripePriceId } }); const price = await priceResponse.json(); return { ...product, price: price || null, }; } catch (error) { console.error(`Failed to fetch data for slug ${slug}:`, error.message); return null; } }) ); const validProducts = enrichedProducts.filter((product) => product !== null); return NextResponse.json(validProducts); } catch (error) { console.error('Error fetching all products:', error.message); return NextResponse.json({ error: 'Failed to fetch products.' }, { status: 500 }); } } then in the update products api request, it does this `revalidateTag('testinggg');`, but nothing is revalidating.
Like in here, you dont need to put tags since you can just use revalidatePath(getProductRoute)
Gray FlycatcherOP
oh i see, as next js caches every api route in next14
i’ll try that
well not every api, but you can try adding these
export const dynamic = 'force-static'
nextjs allows you to set the cache for every route in nextjs.
Gray FlycatcherOP
and will that still allow recalibrate path to revalidate
even tho it’s static
yeah
make sure you aren't using dynamic functions
otherwise you need to set the route as dynamic and cache the functions not the route
@alfonsus make sure you aren't using dynamic functions
Gray FlycatcherOP
wdym by dynamic functions
@Gray Flycatcher i thought you can do like NextResponse.json(thing, {next:{tags:[…]}})
Gray FlycatcherOP
@alfonsus woukd it work by doing this, and putting the tag inside the api route, any requests to that api route use the cache?
@alfonsus you can't put the tags in NextResponse if i remember correctly.
Gray FlycatcherOP
if i use revalidate path and leave the rest as normal, provided fetch requests are done server side, should that work so that every request to that api is cached until revalidated?
@Gray Flycatcher if i use revalidate path and leave the rest as normal, provided fetch requests are done server side, should that work so that every request to that api is cached until revalidated?
if fetch are done server side, and you are hitting your own api, its better to import the function directly rather than making a server request to the same server you are already in.
@alfonsus if fetch are done server side, and you are hitting your own api, its better to import the function directly rather than making a server request to the same server you are already in.
Gray FlycatcherOP
also what do i do instead of getServerSideProps using the app router, rather than pages?
@Gray Flycatcher also what do i do instead of getServerSideProps using the app router, rather than pages?
Just write the data fetching methods directly in page.js or layout.js
@alfonsus Just write the data fetching methods directly in page.js or layout.js
Gray FlycatcherOP
okay so I now have this:
import { GET as getProducts } from '@/app/api/admin/getProducts/route';
import { GET as getBoxes } from '@/app/api/admin/getBoxes/route';
import AdminClientBit from "@/app/components/adminClientBit";

export default async function AdminPage() {
    const {products, boxes} = (await getStuff()).props

    return (
        <AdminClientBit productss={products} boxess={boxes} />
    )
}

async function getStuff() {
    try {
        const products = await (await getProducts()).json();
        const boxes = await(await getBoxes()).json();
        return {
            props: {
                products,
                boxes
            },
        };
    } catch (error) {
        return {
            props: {
                products: [],
                boxes: []
            },
        };
    }
}


/src/app/api/admin/getProducts/route.js
import { NextResponse } from 'next/server';

export const revalidate = false;
export const dynamic = 'force-static'

export async function GET() {

    try {
        //...

        return NextResponse.json(validProducts);
    } catch (error) {
        //...
        return NextResponse.json({ error: 'Failed to fetch products.' }, { status: 500 });
    }
}


then in another route im doing revalidatePath('/api/admin/getProducts'); and its still not revalidating the cache