backend / healthcare regulated / 01_healthcare_data_standards.md

Healthcare data standards: HL7, FHIR, OMOP

6 interview angles 5 min read source

Healthcare data standards: HL7, FHIR, OMOP

Verified 2026-08. Two of the vacancies in scope are healthcare platforms, and both name data normalisation to an international standard as a strategic initiative. This is the vocabulary for that conversation.

The landscape

Standard What it is Where you meet it
HL7 v2 pipe-delimited messages, 1980s, still the workhorse hospital interfaces: admissions, orders, results
HL7 v3 / CDA XML, heavyweight, largely superseded clinical document exchange, some national programmes
FHIR REST + JSON/XML resources modern interoperability, patient apps, EHR APIs
DICOM imaging, with its own network protocol radiology, PACS
X12 EDI transactions US claims and eligibility (837, 835, 270/271)
OMOP CDM a relational analytics model observational research across sites
CDISC (SDTM, ADaM) clinical trial submission formats regulatory submissions to the FDA

The distinction to hold on to: HL7/FHIR are exchange formats; OMOP and CDISC are analytics and submission models. You do not query FHIR to run a cohort study, and you do not exchange OMOP between systems. A platform normalising data “to an international standard” is usually doing one of two different jobs, and asking which one is a good clarifying question.

HL7 v2

MSH|^~\&|LAB|HOSP|EHR|HOSP|20260810093000||ORU^R01|MSG0001|P|2.5.1
PID|1||12345^^^HOSP^MR||DOE^JANE||19800101|F
OBR|1||LAB123|CBC^Complete Blood Count
OBX|1|NM|WBC^White Blood Cells||7.2|10*3/uL|4.0-11.0|N|||F

Segments delimited by carriage return, fields by |, components by ^. MSH is always first and defines the delimiters used by the rest of the message.

What makes it painful in practice, and what interviewers want to hear you have met:

  • It is a framework, not a contract. Optional fields, Z-segments (site-specific extensions) and local code systems mean every integration is bespoke. “We support HL7 v2” means nothing without the site’s interface specification.
  • Transport is usually MLLP over raw TCP, not HTTP — a framing protocol with start and end blocks, and an ACK/NAK per message.
  • Sequencing and duplicates. Messages arrive out of order and get resent. Handlers must be idempotent keyed on the message control id.

In Python: hl7apy or python-hl7 for parsing, and Mirth Connect or an integration engine in front for routing in most real deployments.

FHIR

Resources over REST. Patient, Observation, Encounter, Condition, MedicationRequest, DocumentReference and roughly 150 more.

GET /fhir/Patient?identifier=http://hosp|12345
GET /fhir/Observation?patient=Patient/1&code=http://loinc.org|718-7&_sort=-date&_count=10
{
  "resourceType": "Observation",
  "status": "final",
  "code": { "coding": [{ "system": "http://loinc.org", "code": "718-7", "display": "Hemoglobin" }] },
  "subject": { "reference": "Patient/1" },
  "valueQuantity": { "value": 13.5, "unit": "g/dL", "system": "http://unitsofmeasure.org" }
}

Versions, as of 2026-08: R4 is normative and is what 95%+ of certified EHRs actually implement. R5 is published but has limited adoption. R6 is in ballot, not published — expected 2026-2027, and it is what US Core is being built on next. Build against R4 today and say so; claiming R5 or R6 in production is the kind of detail an interviewer in this space will catch.

Profiles matter more than the base spec. US Core, IPS and national profiles constrain which fields are required and which value sets are allowed. “FHIR-compliant” without naming a profile is close to meaningless — validate against the profile with the HL7 validator or fhir.resources in Python.

Terminology is the real work. LOINC for lab observations, SNOMED CT for clinical findings, RxNorm for medications, ICD-10 for diagnoses. Mapping a site’s local codes to these is where the effort and the errors live, and where a terminology server (or an unglamorous mapping table with provenance) belongs.

Bulk export ($export, the Flat FHIR “backend services” flow) is how you get population-scale data out — asynchronous, producing NDJSON on object storage. Paging through the regular REST API for a million patients does not work.

OMOP CDM

A standardised relational schema (person, visit_occurrence, condition_occurrence, drug_exposure, measurement, observation_period) with all source codes mapped to a single concept vocabulary. The point is that the same analysis SQL runs unchanged across institutions.

Getting there is an ETL problem: extract from the EHR or FHIR, map local codes to OMOP concept ids, and load. The mapping step is where meaning is lost or preserved, and it is the part to talk about — an unmapped code becomes concept 0 and silently disappears from every cohort query.

CDISC SDTM plays the equivalent role for clinical trial submissions, and there is active work on converting between SDTM and OMOP.

Building this in Python

The architecture is an anti-corruption layer, which is the same pattern as any third-party integration:

HL7 v2 / FHIR / CSV extracts
        |
   adapters (one per source, per version)
        |
   canonical internal model  <-- your domain lives here
        |
   OMOP / warehouse / API responses

Never let a FHIR resource shape reach your business logic. Providers differ, versions differ, and a field that is optional in the spec is absent at half your sites. Parse and validate at the boundary into your own Pydantic models, and keep the mapping in one place. See ../../system_design/01_api_integrations/01_integration_design.md.

Keep provenance on every record: which source, which message, which version, which mapping rule. In a regulated setting you will be asked to explain how a value got where it is, and “we transformed it” is not an answer.

Interview angle

  • “HL7 v2 or FHIR?” - FHIR for anything new: REST, JSON, resource-oriented, real tooling. HL7 v2 because hospitals still run on it and will for years. A realistic platform speaks both, with an adapter layer normalising into one internal model.
  • “Which FHIR version would you build against?” - R4. It is normative and is what certified EHRs implement; R5 has limited adoption and R6 is still in ballot as of 2026. Then ask which profile - US Core or a national one - because the profile is what actually constrains the data.
  • “Why is FHIR compliance not enough?” - the base spec makes almost everything optional. Two compliant servers can return completely different data. Conformance is against a profile, validated with the official validator, not against the base resource.
  • “What is the hard part of normalising clinical data?” - terminology mapping. Local codes to LOINC, SNOMED, RxNorm and ICD-10, with provenance for every mapping decision. An unmapped code silently drops out of downstream analysis, which is worse than an error.
  • “FHIR or OMOP for a research warehouse?” - OMOP. FHIR is an exchange format and is a poor analytical query target; OMOP is a relational analytics model designed so the same cohort SQL runs across institutions. They coexist: FHIR in, OMOP for analysis.
  • “How do you handle a resent HL7 message?” - idempotent handling keyed on the message control id, because v2 interfaces resend on ACK timeout and messages arrive out of order. Treat it exactly like an at-least-once queue.