hensei-web/app/api/parties/route.ts
Justin Edmund 1f8de7ee30
Fix Railway build errors by marking dynamic routes (#437)
## Summary
- Fixes Railway deployment build failures caused by dynamic server usage
errors
- Marks routes that use runtime features as `force-dynamic` to prevent
static generation attempts
- Creates proper error pages to handle 404/500 scenarios

## Problem
The build was failing with "Dynamic server usage" errors because Next.js
was trying to statically generate pages that use runtime features like:
- `cookies()` for authentication
- `searchParams` for filtering
- Dynamic data fetching that requires request-time context

## Solution
Added `export const dynamic = 'force-dynamic'` to:

### API Routes
- `/api/jobs/route.ts` - uses searchParams
- `/api/jobs/skills/route.ts` - uses cookies via fetchFromApi
- `/api/version/route.ts` - uses cookies via fetchFromApi
- `/api/raids/groups/route.ts` - uses cookies via fetchFromApi
- `/api/parties/route.ts` - uses searchParams and cookies
- `/api/parties/[shortcode]/route.ts` - uses cookies
- `/api/parties/[shortcode]/remix/route.ts` - uses cookies

### Page Components
- `/app/[locale]/teams/page.tsx` - uses searchParams
- `/app/[locale]/new/page.tsx` - fetches dynamic data
- `/app/[locale]/saved/page.tsx` - uses cookies and searchParams
- Additional pages to avoid useContext errors during static generation

### Error Handling
- Created `/pages/_error.tsx` - Simple error page without i18n
complexity
- Created `/app/not-found.tsx` - App Router 404 page

## Test plan
- [x] Build completes successfully locally with `npm run build`
- [ ] Deploy to Railway staging environment
- [ ] Verify all dynamic routes work correctly
- [ ] Check error pages display properly

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-09-04 02:41:03 -07:00

83 lines
No EOL
2.4 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import { z } from 'zod';
import { fetchFromApi, postToApi, PartySchema } from '~/app/lib/api-utils';
// Force dynamic rendering because we use searchParams and cookies
export const dynamic = 'force-dynamic';
// GET handler for fetching parties with filters
export async function GET(request: NextRequest) {
try {
// Parse URL parameters
const searchParams = request.nextUrl.searchParams;
const element = searchParams.get('element');
const raid = searchParams.get('raid');
const recency = searchParams.get('recency');
const page = searchParams.get('page') || '1';
const username = searchParams.get('username');
// Build query parameters
const queryParams: Record<string, string> = {};
if (element) queryParams.element = element;
if (raid) queryParams.raid_id = raid;
if (recency) queryParams.recency = recency;
if (page) queryParams.page = page;
let endpoint = '/parties';
// If username is provided, fetch that user's parties
if (username) {
endpoint = `/users/${username}/parties`;
}
// Append query parameters
const queryString = new URLSearchParams(queryParams).toString();
if (queryString) {
endpoint += `?${queryString}`;
}
const data = await fetchFromApi(endpoint);
return NextResponse.json(data);
} catch (error: any) {
console.error('Error fetching parties', error);
return NextResponse.json(
{ error: error.message || 'Failed to fetch parties' },
{ status: error.response?.status || 500 }
);
}
}
// Validate party data
const CreatePartySchema = PartySchema.extend({
element: z.number().min(1).max(6),
raid_id: z.string().optional(),
});
// POST handler for creating a new party
export async function POST(request: NextRequest) {
try {
const body = await request.json();
// Validate the request body
const validatedData = CreatePartySchema.parse(body.party);
const response = await postToApi('/parties', {
party: validatedData
});
return NextResponse.json(response);
} catch (error: any) {
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: 'Validation error', details: error.errors },
{ status: 400 }
);
}
return NextResponse.json(
{ error: error.message || 'Failed to create party' },
{ status: error.response?.status || 500 }
);
}
}