feat: add Strapi API client and data fetching functions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
consultoria-as
2026-02-22 03:56:02 +00:00
parent 00d500d3d3
commit bd222376bd
3 changed files with 94 additions and 0 deletions

56
apps/web/src/lib/api.ts Normal file
View File

@@ -0,0 +1,56 @@
import type {
Game,
Documentary,
Chapter,
StrapiListResponse,
StrapiResponse,
} from "@afterlife/shared";
import { strapiGet } from "./strapi";
export async function getGames(locale: string): Promise<StrapiListResponse<Game>> {
return strapiGet({
path: "/games",
locale,
params: {
"populate[coverImage]": "*",
"populate[documentary]": "*",
"sort": "createdAt:desc",
},
});
}
export async function getGameBySlug(slug: string, locale: string): Promise<StrapiResponse<Game>> {
return strapiGet({
path: "/games",
locale,
params: {
"filters[slug][$eq]": slug,
"populate[coverImage]": "*",
"populate[screenshots]": "*",
"populate[documentary][populate][chapters][populate]": "*",
},
});
}
export async function getDocumentaryByGameSlug(
slug: string,
locale: string
): Promise<Documentary | null> {
const gameRes = await getGameBySlug(slug, locale);
const game = Array.isArray(gameRes.data) ? gameRes.data[0] : gameRes.data;
return game?.documentary ?? null;
}
export async function getChapter(
chapterId: number,
locale: string
): Promise<StrapiResponse<Chapter>> {
return strapiGet({
path: `/chapters/${chapterId}`,
locale,
params: {
"populate[audioFile]": "*",
"populate[coverImage]": "*",
},
});
}

View File

@@ -0,0 +1,35 @@
const STRAPI_URL = process.env.STRAPI_URL || "http://localhost:1337";
const STRAPI_TOKEN = process.env.STRAPI_API_TOKEN;
interface FetchOptions {
path: string;
params?: Record<string, string>;
locale?: string;
}
export async function strapiGet<T>({ path, params, locale }: FetchOptions): Promise<T> {
const url = new URL(`/api${path}`, STRAPI_URL);
if (locale) url.searchParams.set("locale", locale);
if (params) {
for (const [key, value] of Object.entries(params)) {
url.searchParams.set(key, value);
}
}
const headers: HeadersInit = { "Content-Type": "application/json" };
if (STRAPI_TOKEN) {
headers.Authorization = `Bearer ${STRAPI_TOKEN}`;
}
const res = await fetch(url.toString(), {
headers,
next: { revalidate: 60 },
});
if (!res.ok) {
throw new Error(`Strapi error: ${res.status} ${res.statusText}`);
}
return res.json();
}