Add FMCSA API fallback for name search when local DB is empty

Tries local fmcsa_carriers table first (ILIKE partial match).
If no results, falls back to FMCSA QCMobile API name search.
Ensures name search works even before full 2M census is loaded.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
justin 2026-05-28 23:37:45 -05:00
parent 69b70ee96d
commit 068739cb20

View file

@ -322,6 +322,7 @@ router.get("/api/v1/dot/search", async (req, res) => {
}
try {
// Try local database first
const result = await pool.query(
`SELECT dot_number, legal_name, dba_name, phy_city, phy_state,
nbr_power_unit, authorized_for_hire, mcs150_parsed
@ -332,9 +333,54 @@ router.get("/api/v1/dot/search", async (req, res) => {
[`%${name}%`],
);
if (result.rows.length > 0) {
res.json({
results: result.rows,
count: result.rows.length,
query: name,
source: "FMCSA Motor Carrier Census",
});
return;
}
// Fallback: FMCSA QCMobile API name search
if (FMCSA_API_KEY) {
try {
const apiResp = await fetch(
`${FMCSA_BASE}/name/${encodeURIComponent(name)}?webKey=${FMCSA_API_KEY}`,
{ signal: AbortSignal.timeout(10000), headers: { Accept: "application/json" } },
);
if (apiResp.ok) {
const apiData = await apiResp.json();
const carriers = (apiData.content || []).map((item: any) => {
const c = item.carrier || item;
return {
dot_number: String(c.dotNumber || ""),
legal_name: c.legalName || "",
dba_name: c.dbaName || null,
phy_city: c.phyCity || null,
phy_state: c.phyState || null,
nbr_power_unit: c.totalPowerUnits || null,
authorized_for_hire: c.allowedToOperate === "Y",
mcs150_parsed: null,
};
});
res.json({
results: carriers.slice(0, 50),
count: carriers.length,
query: name,
source: "FMCSA API (live)",
});
return;
}
} catch {
// API fallback failed — return empty
}
}
res.json({
results: result.rows,
count: result.rows.length,
results: [],
count: 0,
query: name,
source: "FMCSA Motor Carrier Census",
});