← back to Norma
app/api/pulse/petitions/[id]/route.ts
56 lines
import { NextRequest, NextResponse } from 'next/server';
import { query } from '@/lib/db';
type RouteContext = { params: Promise<{ id: string }> };
/**
* GET /api/pulse/petitions/[id]
* PUBLIC API — No auth required.
* Returns a single active petition by ID.
*/
export async function GET(request: NextRequest, context: RouteContext) {
const { id } = await context.params;
// Validate UUID format
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
if (!uuidRegex.test(id)) {
return NextResponse.json({ error: 'Invalid petition ID' }, { status: 400 });
}
try {
const result = await query(
`SELECT id, title, COALESCE(body, description) AS body, description, target, category,
tags, signature_count, signature_goal, is_featured, talking_points, created_at, updated_at
FROM petitions
WHERE id = $1 AND status = 'active'`,
[id]
);
if (result.rowCount === 0) {
return NextResponse.json({ error: 'Petition not found' }, { status: 404 });
}
// Also fetch related petitions (same category, excluding self)
const petition = result.rows[0];
const related = await query(
`SELECT id, title, COALESCE(body, description) AS body, category, signature_count, signature_goal, is_featured
FROM petitions
WHERE status = 'active' AND category = $1 AND id != $2
ORDER BY COALESCE(signature_count, 0) DESC
LIMIT 3`,
[petition.category, id]
);
return NextResponse.json({
petition,
related: related.rows,
});
} catch (err) {
console.error('[api/pulse/petitions/[id]] GET error:', (err as Error).message);
return NextResponse.json(
{ error: 'Failed to fetch petition' },
{ status: 500 }
);
}
}