feat(frontend): add next.tags cache support to apiFetch; tag all GET fetches
This commit is contained in:
@@ -151,9 +151,13 @@ const API_BASE_URL =
|
||||
? process.env.NEXT_PUBLIC_SERVER_SIDE_API_URL
|
||||
: process.env.NEXT_PUBLIC_API_URL;
|
||||
|
||||
type ApiFetchOptions = Omit<RequestInit, 'next'> & {
|
||||
next?: { tags?: string[]; revalidate?: number | false }
|
||||
}
|
||||
|
||||
async function apiFetch<T>(
|
||||
endpoint: string,
|
||||
options: RequestInit = {},
|
||||
options: ApiFetchOptions = {},
|
||||
schema: z.ZodType<T>,
|
||||
token?: string | null
|
||||
): Promise<T> {
|
||||
@@ -161,9 +165,11 @@ async function apiFetch<T>(
|
||||
throw new Error("API_BASE_URL is not defined");
|
||||
}
|
||||
|
||||
const { next, ...restOptions } = options;
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
"Content-Type": "application/json",
|
||||
...(options.headers as Record<string, string>),
|
||||
...(restOptions.headers as Record<string, string>),
|
||||
};
|
||||
|
||||
if (token) {
|
||||
@@ -171,8 +177,9 @@ async function apiFetch<T>(
|
||||
}
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
|
||||
...options,
|
||||
...restOptions,
|
||||
headers,
|
||||
...(next ? { next } : {}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -202,7 +209,7 @@ export const loginUser = (data: z.infer<typeof LoginSchema>) =>
|
||||
// ── Current user ──────────────────────────────────────────────────────────
|
||||
|
||||
export const getMe = (token: string) =>
|
||||
apiFetch("/users/me", {}, MeSchema, token);
|
||||
apiFetch("/users/me", { next: { tags: ['me'] } }, MeSchema, token);
|
||||
|
||||
export const updateProfile = (data: z.infer<typeof UpdateProfileSchema>, token: string) =>
|
||||
apiFetch("/users/me", { method: "PATCH", body: JSON.stringify(data) }, UserSchema, token);
|
||||
@@ -213,13 +220,13 @@ export const getMeFollowingList = (token: string) =>
|
||||
// ── Users ─────────────────────────────────────────────────────────────────
|
||||
|
||||
export const getUserProfile = (username: string, token: string | null) =>
|
||||
apiFetch(`/users/${username}`, {}, UserSchema, token);
|
||||
apiFetch(`/users/${username}`, { next: { tags: [`profile:${username}`] } }, UserSchema, token);
|
||||
|
||||
export const getFollowersList = (username: string, token: string | null) =>
|
||||
apiFetch(`/users/${username}/followers`, {}, z.object({ total: z.number(), items: z.array(UserSchema) }), token);
|
||||
apiFetch(`/users/${username}/followers`, { next: { tags: [`profile:${username}`] } }, z.object({ total: z.number(), items: z.array(UserSchema) }), token);
|
||||
|
||||
export const getFollowingList = (username: string, token: string | null) =>
|
||||
apiFetch(`/users/${username}/following`, {}, z.object({ total: z.number(), items: z.array(UserSchema) }), token);
|
||||
apiFetch(`/users/${username}/following`, { next: { tags: [`profile:${username}`] } }, z.object({ total: z.number(), items: z.array(UserSchema) }), token);
|
||||
|
||||
export const getTopFriends = (username: string, token: string | null) =>
|
||||
apiFetch(
|
||||
@@ -330,7 +337,7 @@ export const getAllUsersCount = () =>
|
||||
export const getFeed = (token: string, page: number = 1, pageSize: number = 20) =>
|
||||
apiFetch(
|
||||
`/feed?page=${page}&per_page=${pageSize}`,
|
||||
{},
|
||||
{ next: { tags: ['feed'] } },
|
||||
z.object({ items: z.array(ThoughtSchema), total: z.number(), page: z.number(), per_page: z.number() })
|
||||
.transform((d) => ({ ...d, totalPages: Math.ceil(d.total / d.per_page) })),
|
||||
token
|
||||
@@ -339,7 +346,7 @@ export const getFeed = (token: string, page: number = 1, pageSize: number = 20)
|
||||
export const getUserThoughts = (username: string, token: string | null) =>
|
||||
apiFetch(
|
||||
`/users/${username}/thoughts`,
|
||||
{},
|
||||
{ next: { tags: [`profile:${username}`] } },
|
||||
z.object({ items: z.array(ThoughtSchema), total: z.number(), page: z.number(), per_page: z.number() }),
|
||||
token
|
||||
);
|
||||
@@ -351,7 +358,7 @@ export const deleteThought = (thoughtId: string, token: string) =>
|
||||
apiFetch(`/thoughts/${thoughtId}`, { method: "DELETE" }, z.null(), token);
|
||||
|
||||
export const getThoughtById = (thoughtId: string, token: string | null) =>
|
||||
apiFetch(`/thoughts/${thoughtId}`, {}, ThoughtSchema, token);
|
||||
apiFetch(`/thoughts/${thoughtId}`, { next: { tags: [`thought:${thoughtId}`] } }, ThoughtSchema, token);
|
||||
|
||||
export const getThoughtThread = async (thoughtId: string, token: string | null): Promise<ThoughtThread> => {
|
||||
const thoughts = await apiFetch(`/thoughts/${thoughtId}/thread`, {}, z.array(ThoughtSchema), token);
|
||||
@@ -375,7 +382,7 @@ export const getThoughtThread = async (thoughtId: string, token: string | null):
|
||||
export const getThoughtsByTag = (tagName: string, token: string | null) =>
|
||||
apiFetch(
|
||||
`/tags/${tagName}`,
|
||||
{},
|
||||
{ next: { tags: [`tag:${tagName}`, 'feed'] } },
|
||||
z.object({ tag: z.string(), items: z.array(ThoughtSchema), total: z.number(), page: z.number(), per_page: z.number() }),
|
||||
token
|
||||
);
|
||||
@@ -391,7 +398,7 @@ export const getPopularTags = () =>
|
||||
// ── Search ────────────────────────────────────────────────────────────────
|
||||
|
||||
export const search = (query: string, token: string | null) =>
|
||||
apiFetch(`/search?q=${encodeURIComponent(query)}`, {}, SearchResultsSchema, token);
|
||||
apiFetch(`/search?q=${encodeURIComponent(query)}`, { next: { tags: ['search'] } }, SearchResultsSchema, token);
|
||||
|
||||
// ── API Keys ──────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
Reference in New Issue
Block a user