1. The “Tab Fatigue” Problem
A doctor needs to check if a new prescription will interact with the patient’s current medications. The drug interaction database wants RxNorm codes. The EHR has the medications stored with local formulary codes. The patient’s research record uses OMOP concept IDs. Three systems, three vocabularies, zero interoperability. The doctor opens another tab. This is “Tab Fatigue” or, as clinicians call it, “Death by a Thousand Clicks.” The insights exist: drug interaction alerts, care gap notifications, clinical trial eligibility signals. But they’re trapped in separate systems that don’t speak the same vocabulary language. Getting data out of an EHR for research is hard. Getting standardized insights back into the EHR at the point of care is the real “Last Mile” problem. The vocabulary translation layer is where OMOPHub fits. When an EHR-integrated application (like a SMART on FHIR app) needs to convert local or FHIR-native codes into standardized OMOP concepts, OMOPHub provides the lookup: search for a code, get back the OMOP concept ID, access its hierarchy and relationships. It’s one component in a larger integration pipeline, not the middleware itself, but the vocabulary resolution step that makes the rest possible. The full FHIR-to-OMOP pipeline looks like this:- FHIR client reads patient data from the EHR (medications, conditions, labs)
- Your application code parses the FHIR resources and extracts coded elements
- OMOPHub resolves those codes to standardized OMOP concept IDs
- Your CDS / analytics engine runs logic against the standardized concepts
2. The Core Concept: Code Resolution at the Point of Care
EHR data arrives in many vocabulary flavors. A medication might be coded in RxNorm, NDC, a local formulary code, or just free text. A diagnosis might be ICD-10-CM in billing, SNOMED in the problem list, or a local shorthand in a quick note. A lab result could use LOINC, a vendor-specific code, or an institution-specific abbreviation. For any clinical decision support to work across EHR installations, these codes need to resolve to a common vocabulary. OMOP provides that common layer - and OMOPHub provides programmatic access to it. The resolution patterns:- Known standard code (e.g., RxNorm “1049502”) →
POST /v1/fhir/resolvewithsystem+code→ standard OMOP concept, CDM target table, mapping type - Local display name (e.g., “Creatinine, Serum”) →
POST /v1/fhir/resolvewithdisplayonly → Resolver falls back to semantic search scoped byresource_type - Free text (e.g., “Chest pain”) → same as above, no
code/system - Proprietary code (e.g., “MED_LOCAL_4827”) → OMOPHub can’t help directly; requires a pre-built local mapping table
3. Use Case A: Real-Time Clinical Decision Support
A SMART on FHIR app needs to check a newly prescribed medication against the patient’s current conditions and medications: all standardized to OMOP concepts. The Scenario: A doctor prescribes Amoxicillin. The app extracts the medication from the FHIRMedicationRequest resource, resolves it to an OMOP concept via OMOPHub, and feeds it to a CDS engine that checks for interactions against the patient’s OMOP-standardized history.
Python
target_table) which OMOP CDM table to write to. The ingredient-level step stays separate because Has ingredient is a non-hierarchical relationship - the right tool is concepts.relationships(), not a hierarchy walk. The Resolver for the ETL leg, the raw primitives for the domain-specific enrichment: two tools for two different shapes of problem.
See also: FHIR Integration guide for the full Resolver response shape (source vs standard concept, mapping_type, alternative_standard_concepts, mapping_quality).
4. Use Case B: Normalizing Local Lab Codes for a Sidecar App
EHR-embedded “sidecar” apps (SMART on FHIR apps for specialty workflows) often need to display standardized trends from lab data that arrives in 50 different local code variants. The Scenario: A CKD management app needs to show creatinine trends. The EHR uses “Cr_Serum,” “Creat_Blood,” and “Kidney_Fx_Creat” - all meaning the same thing. The app needs a single LOINC concept to unify them.Python
POST /v1/fhir/resolve/batch is the natural fit for “N local variants, need the canonical LOINC”. Each display-only input tells the Resolver “I don’t have a coded system - use semantic search scoped to the Observation domain.” The response’s similarity_score and mapping_type: "semantic_match" let you decide which matches to trust (high-similarity: auto-accept; low: surface to the site’s data team for review). Batch counts as N API calls, same as N single resolves, so there’s no pricing penalty for bundling.
Caveat: This only works when the local display name is descriptive enough for semantic search to match. Highly abbreviated codes (like “Cr_S” or “KFC_001”) won’t match anything useful. Those need a pre-built local mapping maintained by the site’s data team - the target_table and mapping_quality: "manual_review" fields in the Resolver response help you route them to the right workflow.
5. The “Feedback Loop”: Writing Back to the EHR
True integration is bidirectional. When your OMOPHub-powered app identifies something - a more precise diagnosis code, a care gap, a trial match - that information should flow back to the EHR. Example: A clinician types “chest pain” in a free-text field. Your app searches OMOPHub and suggests “Angina pectoris” (a specific SNOMED condition concept) with its concept ID and code. The clinician confirms, and the app writes the structured SNOMED code back to the EHR via a FHIR Condition resource. The mechanics of the write-back are handled by the EHR’s FHIR write API - OMOPHub doesn’t write to EHRs. But OMOPHub provides the vocabulary backbone: the standardized concept ID, name, and code that get written back. This closes the loop: messy data comes out of the EHR → OMOPHub standardizes it → your app adds clinical intelligence → clean, structured data goes back in. Over time, this feedback loop improves the EHR data itself - more precise codes, fewer local abbreviations, better downstream analytics. The vocabulary standardization that started as a research need becomes a data quality improvement engine.6. Conclusion: Making Data Invisible (and Useful)
The best clinical technology is invisible. The clinician doesn’t see “FHIR-to-OMOP transformation” or “vocabulary resolution” - they see a drug interaction alert that fires at the right moment, a lab trend that makes sense across visits, a trial match that arrives without a separate login. OMOPHub’s role in this is specific: it resolves codes from EHR-native vocabularies to standardized OMOP concepts via API. It doesn’t parse FHIR resources, run CDS logic, or write back to EHRs. But it provides the vocabulary resolution layer that every other component depends on. And it does so without requiring per-site mapping tables or local vocabulary databases. If you’re building SMART on FHIR apps or EHR-integrated clinical tools, start with the vocabulary problem. Take a FHIR MedicationRequest from your test environment, extract the coded medication, and resolve it through OMOPHub. That single API call - billing code in, standard concept out - is the foundation everything else builds on. The data complexity becomes invisible. The clinical insight becomes useful.7. Next Steps
FHIR Integration
Full reference for the FHIR Resolver (single, batch, CodeableConcept) and the OMOPHub FHIR Terminology Service -
$lookup, $validate-code, $translate, $expand, $subsumes, batch Bundles.EHRbase / openEHR
Terminology-validated openEHR capture: wire EHRbase’s composition validator at OMOPHub via the FHIR Terminology Service so coded fields in openEHR templates are checked at commit time.
HAPI FHIR
Point a HAPI FHIR server at OMOPHub as a remote terminology backend. Covers both the HAPI JPA Starter (reverse-proxy auth pattern) and custom Spring Boot HAPI builds.