From 5e19028ceaa56cfd281c9d43d084577c4a1b27cb Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Fri, 7 Nov 2025 08:11:01 +0100 Subject: [PATCH] refactor(api): improve API error handling and revalidation - Update API utilities to use new ApiError class - Improve error handling and status code management - Enhance revalidation logic for better cache management --- web/src/lib/api.ts | 48 +++++++++++++++++++++++---------------- web/src/lib/revalidate.ts | 22 +++++++++++++++--- 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/web/src/lib/api.ts b/web/src/lib/api.ts index df0e254d..4bd93c15 100644 --- a/web/src/lib/api.ts +++ b/web/src/lib/api.ts @@ -1,25 +1,17 @@ +import { unstable_cache } from "next/cache" import { METADATA_URL } from "@/constants" -import type { IconFile, IconWithName } from "@/types/icons" - -/** - * Custom error class for API errors - */ -export class ApiError extends Error { - status: number - - constructor(message: string, status = 500) { - super(message) - this.name = "ApiError" - this.status = status - } -} +import { ApiError } from "@/lib/errors" +import type { AuthorData, IconFile, IconWithName } from "@/types/icons" /** * Fetches all icon data from the metadata.json file + * Uses fetch with revalidate for caching */ export async function getAllIcons(): Promise { try { - const response = await fetch(METADATA_URL) + const response = await fetch(METADATA_URL, { + next: { revalidate: 3600 }, + }) if (!response.ok) { throw new ApiError(`Failed to fetch icons: ${response.statusText}`, response.status) @@ -93,16 +85,14 @@ export async function getIconData(iconName: string): Promise { + return unstable_cache( + async () => await fetchAuthorData(authorId), + [`author-${authorId}`], + { + revalidate: 86400, + tags: ["authors", `author-${authorId}`], + } + )() +} + /** * Fetches total icon count */ diff --git a/web/src/lib/revalidate.ts b/web/src/lib/revalidate.ts index 80d8399c..4389ea37 100644 --- a/web/src/lib/revalidate.ts +++ b/web/src/lib/revalidate.ts @@ -1,21 +1,37 @@ "use server" -import { revalidatePath, revalidateTag } from "next/cache" +import { revalidatePath, updateTag } from "next/cache" /** * Revalidate the community page cache * Can be called from server actions after submission approval/rejection + * Uses updateTag for immediate updates (read-your-writes semantics) */ export async function revalidateCommunityPage() { revalidatePath("/community") - revalidateTag("community-gallery") + updateTag("community-gallery") +} + +/** + * Revalidate a specific community icon page + * Use this when a specific submission's status changes + * Uses updateTag for immediate updates (read-your-writes semantics) + */ +export async function revalidateCommunityIcon(iconName: string) { + revalidatePath(`/community/${iconName}`) + updateTag("community-gallery") + updateTag("community-submission") + updateTag("community-gallery-record") } /** * Revalidate all submission-related caches + * Uses updateTag for immediate updates (read-your-writes semantics) */ export async function revalidateSubmissions() { - revalidateTag("community-gallery") + updateTag("community-gallery") + updateTag("community-submission") + updateTag("community-gallery-record") revalidatePath("/community") revalidatePath("/dashboard") }