← back to AbramsOS

lib/fda-fetcher.js

46 lines

// openFDA drug-enforcement (recall) lookup. Free public API — a drug NAME is not
// identifying, so no PHI leaves the box beyond the med name itself (same posture as
// checking whether a product you own was recalled). Optional OPENFDA_API_KEY raises
// the rate limit but is not required.

const BASE = 'https://api.fda.gov/drug/enforcement.json';

function isoFromFdaDate(d) {
  // openFDA dates are YYYYMMDD strings
  if (!d || d.length !== 8) return null;
  return `${d.slice(0, 4)}-${d.slice(4, 6)}-${d.slice(6, 8)}`;
}

function normalize(r) {
  return {
    recall_number: r.recall_number || null,
    classification: r.classification || null,
    status: r.status || null,
    reason: r.reason_for_recall || null,
    product_description: r.product_description || null,
    recall_initiation_date: isoFromFdaDate(r.recall_initiation_date),
    url: r.recall_number
      ? `https://www.accessdata.fda.gov/scripts/ires/index.cfm?Product=${encodeURIComponent(r.recall_number)}`
      : 'https://www.fda.gov/drugs/drug-safety-and-availability/drug-recalls',
    raw: r,
  };
}

// Look up recalls for a single medication name. Matches brand OR generic OR
// product description. Returns [] when the FDA has no matching recall (404).
async function fetchDrugRecalls(name, { limit = 10 } = {}) {
  if (!name) return [];
  const q = String(name).trim().replace(/"/g, '');
  const search = `openfda.brand_name:"${q}"+openfda.generic_name:"${q}"+product_description:"${q}"`;
  const key = process.env.OPENFDA_API_KEY ? `&api_key=${process.env.OPENFDA_API_KEY}` : '';
  const url = `${BASE}?search=${encodeURIComponent(search).replace(/%2B/g, '+')}&limit=${limit}${key}`;

  const res = await fetch(url, { headers: { 'User-Agent': 'AbramsOS/1.0 (personal household admin)' } });
  if (res.status === 404) return [];               // openFDA returns 404 for "no matches"
  if (!res.ok) throw new Error(`openFDA ${res.status}`);
  const json = await res.json();
  return (json.results || []).map(normalize);
}

module.exports = { fetchDrugRecalls, normalize };