Files
0pt/app/api/vehicles/route.ts
admin 5137bf87a1
CI (SIAX Cloud) / integration (push) Skipped
CI (SIAX Cloud) / sonar (push) Skipped
masterplan-lock / check (push) Successful in 4s
CI (SIAX Cloud) / sonar (pull_request) Skipped
CI (SIAX Cloud) / security (push) Successful in 15s
masterplan-lock / check (pull_request) Successful in 7s
Security Scan (SIAX Cloud) / security (push) Successful in 18s
Security Scan (SIAX Cloud) / security (pull_request) Successful in 17s
CI (SIAX Cloud) / security (pull_request) Successful in 20s
CI (SIAX Cloud) / integration (pull_request) Successful in 35s
CI (SIAX Cloud) / quality (pull_request) Successful in 39s
CI (SIAX Cloud) / quality (push) Successful in 48s
fix: distinguish failed sources from empty results
2026-11-02 06:58:15 +01:00

31 lines
1.9 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import { engineFetch, hasEngine } from "@/lib/engine";
// A missing record is distinct from an unavailable or malformed source.
export async function GET(req: NextRequest) {
const plate = (req.nextUrl.searchParams.get("plate") ?? "").toUpperCase().replace(/[-\s]/g, "").replace(/[^A-Z0-9]/g, "");
if (!plate) return NextResponse.json({ error: { code: "bad_request", message: "plate krävs" } }, { status: 400 });
const unavailable = () => NextResponse.json({ error: { code: "source_unavailable", message: "Fordonskällan är inte tillgänglig" } }, { status: 503 });
try {
if (hasEngine()) {
const eng = await engineFetch(`/vehicles/${plate}`);
if (!eng?.ok) return unavailable();
const data: unknown = await eng.json();
if (!data || typeof data !== "object" || Array.isArray(data) || (data as { source_status?: unknown }).source_status !== "ok") return unavailable();
return NextResponse.json(data);
}
const r = await fetch(`https://opendata.rdw.nl/resource/m9d7-ebf2.json?kenteken=${encodeURIComponent(plate)}`, {
headers: { "User-Agent": "0pt/0.1 (+https://0pt.app; SIAX)" }, cache: "no-store",
});
if (!r.ok) return unavailable();
const data: unknown = await r.json();
if (!Array.isArray(data) || data.some((item) => !item || typeof item !== "object" || Array.isArray(item))) return unavailable();
if (!data.length) return NextResponse.json({ vehicle: null });
const d = data[0] as Record<string, string>;
if (d.datum_eerste_toelating != null && typeof d.datum_eerste_toelating !== "string") return unavailable();
return NextResponse.json({ source: "rdw", vehicle: { reg_plate: plate, market: "NL", make: d.merk ?? null,
model: d.handelsbenaming ?? null, year: (d.datum_eerste_toelating ?? "").slice(0, 4) || null },
provenance: { level: 3, source: "rdw" } });
} catch { return unavailable(); }
}