#Serving Google Fonts from the FileSystem instead of fetching from the Google API

1 messages · Page 1 of 1 (latest)

solar meteor
#

Context:

Hi, everyone. I’m integrating the Google Fonts API to a project which has a Font Picker, I want to support the whole Google Font catalogue.

First I was doing fetch requests directly to the Google Fonts API with React Query (useInfiniteQuery) + API route, the traditional set up. But then i thought that Google Fonts don’t change often and it didn’t make sense to fetch the data fresh on every interaction.

The way Figma and Canva seem to do this is by serving the Fonts from a CDN, but I don’t have this infrastructure.

Options:

  1. Make the fetch to Google Fonts API but make sure this gets Cached by Next.js so users always get the same data back. The endpoint will still need to be Hit on every user interaction (to filter via category or name)

  2. Run a script that fetches only once from the Google Fonts API and writes to my fileSystem a HUGE JSON file (20 000 lines) and locally filter and paginate the JSON on each request.

Since the filtering and pagination is done in the API route in both cases, what would you do to solve this issue?

Thank you in advance!

livid kelpBOT
#

🔎 This post has been indexed in our web forum and will be seen by search engines so other users can find it outside Discord

🕵️ Your user profile is private by default and won't be visible to users outside Discord, if you want to be visible in the web forum you can add the "Public Profile" role in id:customize

✅ You can mark a message as the answer for your post with Right click -> Apps -> Mark Solution
(if you don't see the option, try refreshing Discord with Ctrl + R)

river chasm
#

i'd say do the api one. The json is bound to go wrong. And its more expensive on IO on e.g. vercel

solar meteor
#

I ended up doing this:

  1. I have a function that fetches the whole Google Fonts catalogue and caches the results indefinitely (this is what I want)
  2. I call an Route Handler with useInfiniteQuery to filter and paginate in memory, using the cached return value of the Google API.

So, I got rid of the huge JSON and let Next.js cache layer handle it, at the end it achieves the same goal, I only ever want this fetch to occur once ever, and all requests will re-use the cache results.

#
const cachedFetchGoogleFonts = unstable_cache(fetchGoogleFonts, ["google-fonts-catalogue"], {
  tags: ["google-fonts-catalogue"],
});

export async function GET(request: NextRequest) {
  try {
    const { searchParams } = new URL(request.url);
    const query = searchParams.get("q")?.toLowerCase() || "";
    const category = searchParams.get("category")?.toLowerCase();
    const limit = Math.min(Number(searchParams.get("limit")) || 50, 100);
    const offset = Number(searchParams.get("offset")) || 0;

    let googleFonts = FALLBACK_FONTS;

    try {
      googleFonts = await cachedFetchGoogleFonts(process.env.GOOGLE_FONTS_API_KEY);
    } catch (error) {
      console.error("Error fetching Google Fonts:", error);
      console.log("Using fallback fonts");
    }

    // Filter fonts based on search query and category
    let filteredFonts = googleFonts;

    if (query) {
      filteredFonts = filteredFonts.filter((font) => font.family.toLowerCase().includes(query));
    }

    if (category && category !== "all") {
      filteredFonts = filteredFonts.filter((font) => font.category === category);
    }

    const paginatedFonts = filteredFonts.slice(offset, offset + limit);

    const response: PaginatedFontsResponse = {
      fonts: paginatedFonts,
      total: filteredFonts.length,
      offset,
      limit,
      hasMore: offset + limit < filteredFonts.length,
    };

    return NextResponse.json(response);
  } catch (error) {
    console.error("Error in Google Fonts API:", error);
    return NextResponse.json({ error: "Failed to fetch fonts" }, { status: 500 });
  }
}
#

Now data lives in .next folder, but I'm not longer responsible of it, and It's only ever fetched once 😄