Next.js Discord

Discord Forum

Next 14 Caching my own api requests

Unanswered
Gray Flycatcher posted this in #help-forum
Open in Discord
Avatar
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

Avatar
West African Lion
Avatar
Gray FlycatcherOP
i used that as well
Avatar
what does your code looks like?
Avatar
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.
Avatar
Where is this code being used?
Avatar
Gray FlycatcherOP
i’m calling the api request inside the code for a page, in a use effect
Avatar
those tags wont work in client-side fetches
you have to put it in the server
Avatar
Gray FlycatcherOP
ohh right so do I have to put it in a server side prop or smth
Avatar
yeuh
you uhh
you can put the tags here.
Avatar
Gray FlycatcherOP
yeah in the next response
Avatar
no not in the next response
Avatar
Gray FlycatcherOP
i thought you can do like NextResponse.json(thing, {next:{tags:[…]}})
also wdym by here
Avatar
Like in here, you dont need to put tags since you can just use revalidatePath(getProductRoute)
Avatar
Gray FlycatcherOP
oh i see, as next js caches every api route in next14
i’ll try that
Avatar
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.
Avatar
Gray FlycatcherOP
and will that still allow recalibrate path to revalidate
even tho it’s static
Avatar
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
Avatar
Gray FlycatcherOP
wdym by dynamic functions
Avatar
Gray FlycatcherOP
@Alfonsus Ardani woukd it work by doing this, and putting the tag inside the api route, any requests to that api route use the cache?
Avatar
you can't put the tags in NextResponse if i remember correctly.
Avatar
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?
Avatar
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.
Avatar
Gray FlycatcherOP
also what do i do instead of getServerSideProps using the app router, rather than pages?
Avatar
Just write the data fetching methods directly in page.js or layout.js
Avatar
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
Avatar
where did you put revalidatePath ?