Files
portfolio/app/api/content/page/route.ts
denshooter 48a29cd872
All checks were successful
CI / CD / test-build (push) Successful in 10m11s
CI / CD / deploy-dev (push) Has been skipped
CI / CD / deploy-production (push) Successful in 1m28s
fix: pass locale explicitly to Hero and force-dynamic on locale-sensitive API routes
- Hero.tsx: pass locale prop directly to getTranslations instead of
  relying on setRequestLocale async storage, which can be lost during
  Next.js RSC streaming
- book-reviews route: replace revalidate=300 with force-dynamic to
  prevent cached English responses being served to German locale requests
- content/page route: add runtime=nodejs and force-dynamic (was missing
  both, violating CLAUDE.md API route conventions)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 13:43:26 +01:00

62 lines
2.1 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import { getContentByKey } from "@/lib/content";
import { getContentPage } from "@/lib/directus";
import { richTextToSafeHtml } from "@/lib/richtext";
export const runtime = 'nodejs';
export const dynamic = 'force-dynamic';
const CACHE_TTL = 300; // 5 minutes
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url);
const key = searchParams.get("key");
const locale = searchParams.get("locale") || "en";
if (!key) {
return NextResponse.json({ error: "key is required" }, { status: 400 });
}
try {
// 1) Try Directus first
const directusPage = await getContentPage(key, locale);
if (directusPage) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const html = directusPage.content ? richTextToSafeHtml(directusPage.content as any) : "";
return NextResponse.json(
{
content: {
title: directusPage.title,
slug: directusPage.slug,
locale: directusPage.locale || locale,
content: directusPage.content,
html,
},
source: "directus",
},
{ headers: { "Cache-Control": `public, s-maxage=${CACHE_TTL}, stale-while-revalidate=${CACHE_TTL * 2}` } }
);
}
// 2) Fallback: PostgreSQL
const translation = await getContentByKey({ key, locale });
if (!translation) {
return NextResponse.json(
{ content: null },
{ headers: { "Cache-Control": `public, s-maxage=${CACHE_TTL}, stale-while-revalidate=${CACHE_TTL * 2}` } }
);
}
return NextResponse.json(
{ content: translation, source: "postgresql" },
{ headers: { "Cache-Control": `public, s-maxage=${CACHE_TTL}, stale-while-revalidate=${CACHE_TTL * 2}` } }
);
} catch (error) {
// If DB isn't migrated/available, fail soft so the UI can fall back to next-intl strings.
if (process.env.NODE_ENV === "development") {
console.warn("Content API failed; returning null content:", error);
}
return NextResponse.json({ content: null });
}
}