← back to Stayclaim
src/app/api/la-records/lookup/route.ts
61 lines
/**
* Live LA County records lookup endpoint.
*
* Used by the /submit form to show a real-time preview of what we know about
* a typed address — year built, sqft, lot size, assessed value — so the user
* sees product value before they hit submit.
*
* Server-side wrapper around lib/la-arcgis.ts. Cache-first via la_parcel table.
*/
import { NextResponse } from 'next/server';
import { getOrFetchParcelForAddress } from '@/lib/la-arcgis';
import { rateLimit } from '@/lib/rate-limit';
export const runtime = 'nodejs';
export const dynamic = 'force-dynamic';
export async function GET(req: Request) {
const rl = await rateLimit('la-records');
if (!rl.ok) {
return NextResponse.json(
{ ok: false, error: 'rate_limited' },
{ status: 429, headers: { 'Retry-After': String(rl.retryAfter ?? 60) } },
);
}
const { searchParams } = new URL(req.url);
const q = searchParams.get('q')?.trim();
if (!q || q.length < 6) {
return NextResponse.json({ ok: false, error: 'query too short' }, { status: 400 });
}
if (q.length > 200) {
return NextResponse.json({ ok: false, error: 'query too long' }, { status: 400 });
}
try {
const parcel = await getOrFetchParcelForAddress(q, null);
if (!parcel) {
return NextResponse.json({ ok: true, found: false });
}
return NextResponse.json({
ok: true,
found: true,
apn: parcel.apn,
situs_address: parcel.situs_address,
city: parcel.city,
zip: parcel.zip,
year_built: parcel.year_built,
sqft_main: parcel.sqft_main,
bedrooms: parcel.bedrooms,
bathrooms: parcel.bathrooms,
use_description: parcel.use_description,
total_value: parcel.total_value,
roll_year: parcel.roll_year,
lat: parcel.lat,
lng: parcel.lng,
});
} catch (e) {
console.error('[la-records/lookup] error', e);
return NextResponse.json({ ok: false, error: 'lookup_failed' }, { status: 500 });
}
}