Blog
PreviousNext

Navigating FHIR in Real-World Systems

A practical, experience-driven look at working with FHIR in real healthcare systems, beyond the specification and surface-level tutorials. It covers the concepts, trade-offs, and lessons that matter when building interoperable, compliant software in the real world.

Taking Notes

Healthcare software is different. Not just because the domain is complex, but because mistakes have consequences that extend far beyond broken screens or failed deployments. When I first started working with FHIR, I assumed the hard part would be learning the specification. I was wrong.

The real challenge was learning how to think in FHIR.

Due to NDA constraints, I can’t talk about the exact system or product I worked on. What I can share are the lessons - what worked, what didn’t, and what I wish I had understood earlier when building applications on top of the FHIR standard.

This post is not a tutorial, but a field guide.

What is FHIR, Really?

FHIR (Fast Healthcare Interoperability Resources) is a healthcare data standard developed by HL7 to enable interoperable exchange of electronic health information.

At a surface level, FHIR looks like:

  • JSON or XML

  • REST APIs

  • HTTP verbs

  • Familiar web concepts

This familiarity is intentional. FHIR was designed to be approachable to modern developers while still satisfying the rigor required in healthcare systems.

But FHIR is not just a data format or an API spec. It’s a domain model, a contract, and a philosophy about how healthcare data should be represented, exchanged, and constrained.

Why FHIR Exists (And Why It Matters)

Before FHIR, healthcare interoperability was dominated by heavyweight standards like HL7 v2 and CDA - powerful, but brittle, opaque, and unfriendly to modern development workflows.

FHIR exists to solve several systemic problems:

  • Fragmented patient data across systems

  • High integration costs between vendors

  • Poor developer experience

  • Slow innovation cycles in healthcare IT

By standardizing how data is modeled and how it is exchanged, FHIR enables:

  • Easier system-to-system integration

  • Patient-facing apps (portals, mobile apps)

  • Clinical decision support

  • Public health reporting

  • Interoperable ecosystems instead of vendor lock-in

FHIR isn’t perfect - but it’s a massive step forward.

Core Design Principles That Shape Everything

If you don’t internalize FHIR’s design philosophy early, everything will feel awkward later.

1. Resource-Based Modeling

FHIR represents healthcare data as resources - small, well-defined building blocks.

Examples:

  • Patient
  • Observation
  • Encounter
  • Medication
  • Practitioner

Each resource is:

  • Independently addressable
  • Versionable
  • Linkable to other resources

This sounds obvious until you try to model something “simple” and realize it spans five resources.

That’s intentional.


2. RESTful by Default

FHIR embraces REST as a first-class interface:

GET /Patient/123 POST /Observation PUT /Encounter/456 DELETE /Medication/789

Search is also standardized:

GET /Observation?patient=123&code=loinc|718-7

This makes FHIR servers feel familiar - but don’t mistake familiarity for simplicity. The complexity lives in search semantics, chaining, and filter behavior.


3. Extensible, Not Rigid

FHIR explicitly acknowledges that no standard can predict every healthcare use case.

Instead of breaking compatibility, FHIR allows:

  • Extensions
  • Profiles
  • Custom constraints

This flexibility is powerful - and dangerous if misused.

Understanding FHIR Resources

This is where most people would struggle. If you don't know already, FHIR defines 150+ resources, grouped broadly into:

  • Clinical
  • Administrative
  • Financial
  • Infrastructure

Some lessons I learned the hard way:

A Patient Is Not Just a Patient

{ "resourceType": "Patient", "id": "123", "name": [{ "family": "Doe", "given": ["John"] }], "gender": "male", "birthDate": "1985-02-17" }

This looks simple - but:

  • Patient demographics live here
  • Clinical data does not
  • Relationships are references, not embeds

FHIR aggressively avoids duplication. It is like an interconnected graph.


Observations Are Everywhere

Vitals, lab results, symptoms - all often represented as Observation.

{ "resourceType": "Observation", "status": "final", "code": { "coding": [{ "system": "http://loinc.org", "code": "718-7", "display": "Hemoglobin" }] }, "subject": { "reference": "Patient/123" }, "valueQuantity": { "value": 13.5, "unit": "g/dL" } }

You’ll quickly learn:

  • Choosing the right resource matters
  • Misusing a resource leads to downstream pain
  • FHIR prefers semantic correctness over convenience

Data Types: Small Details, Big Impact

FHIR data types are deceptively important.

Primitive vs Complex Types

Primitive:

  • string
  • boolean
  • date
  • decimal

Complex:

  • HumanName
  • Address
  • CodeableConcept
  • Reference

Example:

"code": { "coding": [{ "system": "http://snomed.info/sct", "code": "44054006", "display": "Diabetes mellitus" }] }

Why this matters:

  • CodeableConcept supports multiple codings
  • You’re not choosing strings - you’re choosing semantics

References Are First-Class Citizens

FHIR avoids nesting deeply. Instead, it uses references:

"subject": { "reference": "Patient/123" }

This forces you to think in graphs, not documents.

Lesson learned:

Treat FHIR as a connected graph of resources, not a single payload.

Profiles, Bundles, and Extensions (The Real Power Tools)

Profiles: FHIR’s Hidden Backbone

Profiles let you constrain a resource for a specific use case.

Example constraints:

  • Required fields
  • Allowed code systems
  • Cardinality rules

Without profiles:

  • Everyone implements FHIR differently
  • Interoperability collapses

In practice, most production systems rely heavily on profiles - even if they don’t advertise it.


Bundles: Moving Data Together

FHIR Bundles package multiple resources into a single payload.

{ "resourceType": "Bundle", "type": "transaction", "entry": [ { "resource": { "resourceType": "Patient" }}, { "resource": { "resourceType": "Observation" }} ] }

Use cases:

  • Transactions
  • Search results
  • Batch operations

Lesson learned:

Bundles are not just containers - they define processing semantics.


Extensions: Use Sparingly, Think Carefully

Extensions allow custom fields without breaking compatibility.

"extension": [{ "url": "http://example.org/fhir/StructureDefinition/custom-flag", "valueBoolean": true }]

They’re necessary - but overuse leads to:

  • Fragmentation
  • Vendor-specific logic
  • Maintenance complexity

Rule of thumb:

If you need many extensions, revisit your modeling choice.

Real-World Use Cases I Saw

FHIR shines when used correctly.

Common scenarios:

  • Patient portals pulling consolidated data
  • Clinical decision support engines
  • Reporting pipelines for public health
  • Third-party apps via SMART on FHIR

The biggest win?

Decoupling systems without losing semantic meaning.


Security, Privacy, and Compliance

This is where the complexity lies - where things get serious. FHIR is designed to work with modern security standards.

OAuth 2.0 Everywhere

FHIR APIs typically use OAuth 2.0 with scopes like:

patient/Observation.read user/Patient.write

Lesson learned:

  • Authorization is resource-level, not endpoint-level
  • Scope design is critical

FHIR includes resources like:

  • Consent
  • Provenance
  • AuditEvent

Ignoring them early creates compliance debt later.

FHIR aligns well with:

  • HIPAA
  • GDPR
  • ONC / CMS interoperability rules

But alignment ≠ compliance.
You still need policy, governance, and audits.

Tooling and Learning Path

These are few points that will actually help you.

FHIR Servers

  • HAPI FHIR (excellent for learning and prototyping)
  • Commercial servers (varies widely)

Testing & Exploration

  • Postman with FHIR collections
  • Public sandbox servers
  • Validation tools

Documentation

Start with:

  • HL7 FHIR spec (slow, but authoritative)
  • Community examples
  • Real payloads over theory

Best advice:

Build something small, break it, inspect real responses.

Final Reflections

FHIR rewards patience and humility.

You don’t “finish learning” FHIR - you gradually stop fighting it.

The biggest shift for me wasn’t technical. It was mental:

  • From schemas to semantics
  • From payloads to graphs
  • From convenience to correctness

FHIR forces you to respect the domain.
And in healthcare, that’s not a bad thing.

If you’re starting out:

  • Expect friction
  • Embrace constraints
  • Model carefully
  • Validate relentlessly

The standard won’t save you - but used well, it gives you a fighting chance to build systems that matter.

Gangeya writes about software through the lens of experience, and enjoys building things, understanding why they work, and reflecting on what real-world experience teaches beyond frameworks and tools.