raw vPIC response → typed common model

Decode a VIN. Watch the noise become a clean, typed model.

NHTSA’s vPIC API returns ~150 loosely-typed fields per VIN — most empty or "Not Applicable". This demo reshapes that into one consistent Vehicle contract, the same way a telematics API normalizes a messy external source into a common model.

GET /api/decode
Try:

17 chars · A–Z (no I/O/Q) and 0–9 · ⌘/Ctrl + Enter to decode

What the normalization layer does

A single pure function, normalize(raw, vin), owns every rule below. It is the valuable, testable core — everything else is plumbing.

01

Empties become null

"", "Not Applicable", and whitespace-only values all collapse to a single null. "0" is kept on purpose — vPIC uses ErrorCode "0" to mean a clean decode.

02

Typed coercion

ModelYear, Doors, and EngineCylinders are coerced to numbers and DisplacementL to a float. Anything absent or non-numeric returns null, never NaN.

03

GVWR is parsed

The weight rating "Class 8: 33,001 lb and above" is split into gvwrClass ("Class 8") plus the full original range text — structure recovered from a string.

04

Quality is preserved

vPIC's ErrorCode and ErrorText are always carried through, so the consumer of the common model can judge data quality for itself.

The common model

Every consumer codes against this typed contract — never against raw vPIC.

interface Vehicle {
  vin: string;
  make: string | null;
  model: string | null;
  year: number | null;
  vehicleType: string | null;
  bodyClass: string | null;
  gvwrClass: string | null;      // parsed from GVWR, e.g. "Class 8"
  gvwrRange: string | null;      // the raw GVWR range text
  fuelTypePrimary: string | null;
  fuelTypeSecondary: string | null;
  driveType: string | null;
  engineCylinders: number | null;
  displacementL: number | null;
  manufacturer: string | null;
  plantCountry: string | null;
  doors: number | null;
  errorCode: string | null;      // vPIC data-quality signal
  errorText: string | null;
}