54 lines
1.6 KiB
TypeScript
54 lines
1.6 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server';
|
|
import { getTechStack } from '@/lib/directus';
|
|
import { checkRateLimit, getClientIp } from '@/lib/auth';
|
|
|
|
export const runtime = 'nodejs';
|
|
|
|
const CACHE_TTL = 300; // 5 minutes
|
|
|
|
/**
|
|
* GET /api/tech-stack
|
|
*
|
|
* Loads Tech Stack from Directus with fallback to static data
|
|
*
|
|
* Query params:
|
|
* - locale: en or de (default: en)
|
|
*/
|
|
export async function GET(request: NextRequest) {
|
|
// Rate Limit: 60 requests per minute
|
|
const ip = getClientIp(request);
|
|
if (!checkRateLimit(ip, 60, 60000)) {
|
|
return NextResponse.json({ error: 'Rate limit exceeded' }, { status: 429 });
|
|
}
|
|
|
|
try {
|
|
const { searchParams } = new URL(request.url);
|
|
const locale = searchParams.get('locale') || 'en';
|
|
|
|
// Try to load from Directus
|
|
const techStack = await getTechStack(locale);
|
|
|
|
if (techStack && techStack.length > 0) {
|
|
return NextResponse.json(
|
|
{ techStack, source: 'directus' },
|
|
{ headers: { 'Cache-Control': `public, s-maxage=${CACHE_TTL}, stale-while-revalidate=${CACHE_TTL * 2}` } }
|
|
);
|
|
}
|
|
|
|
// Fallback: return empty (component will use hardcoded fallback)
|
|
return NextResponse.json(
|
|
{ techStack: null, source: 'fallback' },
|
|
{ headers: { 'Cache-Control': `public, s-maxage=${CACHE_TTL}, stale-while-revalidate=${CACHE_TTL * 2}` } }
|
|
);
|
|
|
|
} catch (error) {
|
|
if (process.env.NODE_ENV === 'development') {
|
|
console.error('Error loading tech stack:', error);
|
|
}
|
|
return NextResponse.json(
|
|
{ techStack: null, error: 'Failed to load tech stack', source: 'error' },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|