Skip to content
Healthcare IT Architecture
9 min readPublished 2026-09-15

Architecting HL7 and FHIR Interoperability in Modern Hospital Information Systems

A technical blueprint for bidirectional TCP/IP MLLP socket listeners, FHIR R4 JSON pipeline transformations, and laboratory analyzer automation.

Andrew Le Verified Author

Founder & Principal Healthcare Systems Architect

Enterprise healthcare software architect with over 15 years leading hospital information system deployments, HL7/FHIR integrations, and distributed medical software platforms.

Direct Architecture Definition (AI-SEO v2.5)

HL7 and FHIR interoperability enables bidirectional clinical data exchange across electronic medical records, automated laboratory analyzers, and hospital information systems. By deploying Minimal Lower Layer Protocol (MLLP) TCP/IP listeners and FHIR RESTful conversion microservices, hospital engineering teams eliminate diagnostic data silos, maintain regulatory compliance, and deliver real-time longitudinal patient records.

Key Architectural Takeaways

Bidirectional Minimal Lower Layer Protocol (MLLP) TCP/IP socket listening for high-throughput HL7 v2 message streams
Dynamic schema transformation converting pipe-delimited v2 segments (PID, OBR, OBX) into FHIR R4 JSON resources
Securing FHIR API endpoints with SMART on FHIR OAuth 2.0 and asymmetric cryptographic token validation
Direct diagnostic analyzer interfacing with Sysmex, Roche, and Abbott instruments with sub-second order-to-result latency

HL7 v2 MLLP to FHIR R4 Ingestion Pipeline Architecture

Architecture Topology
ascii
+-----------------------+           +-----------------------+           +-----------------------+
|  Laboratory Analyzer  |   MLLP    |  DSF Interop Bridge   |   REST    |  DSF Hospital Suite   |
|  (Sysmex / Roche /    |  TCP/IP   |  (ASP.NET Core Worker |  FHIR R4  |  (PostgreSQL + Core   |
|   Abbott Diagnostics) |  Socket   |   Parser & Validator) |   JSON    |   Clinical Engine)    |
+-----------------------+           +-----------------------+           +-----------------------+
            |                                   |                                   |
            |--- 1. HL7 v2.5 ORU_R01 Message -->|                                   |
            |    (Pipe-delimited MLLP Frame)    |                                   |
            |                                   |--- 2. Parse Segments (PID, OBX) ->|
            |                                   |--- 3. Validate LOINC & SNOMED --->|
            |                                   |--- 4. Transform to Observation -->|
            |<-- 5. MLLP MSA ACK (CA/AA) -------|                                   |
            |    (Commit Acknowledgment)        |                                   |
            |                                   |--- 6. POST /fhir/r4/Observation ->|
            |                                   |    (SMART OAuth2 Bearer Token)    |
            |                                   |                                   |
            |                                   |<-- 7. HTTP 201 Created (UID) -----|
            |                                   |                                   |
            |                                   |--- 8. Emit EMR WebSocket Event -->|
            |                                   |    (Clinician Dashboard Push)     |

Bidirectional clinical telemetry from laboratory analyzers through the DSF Integration Bridge to Hospital Suite database store.

1. The Healthcare Interoperability Landscape: HL7 v2 vs. FHIR R4

Modern hospital networks operate across a hybrid spectrum of technological generations. While modern web applications, mobile patient portals, and health analytics platforms standardize on RESTful FHIR R4 (Fast Healthcare Interoperability Resources) formatted in JSON, the physical reality of acute healthcare infrastructure remains rooted in HL7 v2.x pipe-delimited messaging over raw TCP/IP sockets.

Biomedical hardware—including hematology counters, automated chemistry analyzers, vital sign monitors, and PACS image modalities—predominantly emit HL7 v2.3 through v2.5.1 messages via the Minimal Lower Layer Protocol (MLLP). Attempting to replace these multi-million dollar diagnostic instruments is economically impossible for hospitals. Therefore, the engineering challenge is to build a high-performance, fault-tolerant translation bridge that ingests raw MLLP streams, validates data integrity, and normalizes segments into FHIR resources.

Structural Differences Between Standards

HL7 v2 is event-driven and procedural. A clinical event triggers a message composed of segments (e.g., MSH, PID, PV1, OBR, OBX), separated by carriage returns, with fields delimited by vertical pipes (|). There is no native encryption, no schema validation, and extensive local customization.

FHIR R4 is resource-centric and web-native. Each clinical concept—Patient, Encounter, Observation, DiagnosticReport—exists as a distinct URI with formal JSON schemas, rich data types, extensible coding systems (LOINC, SNOMED CT, RxNorm), and RESTful CRUD operations protected by OAuth 2.0.

2. High-Throughput MLLP TCP/IP Socket Implementation

The Minimal Lower Layer Protocol wraps an HL7 v2 payload with framing bytes: Start Block (0x0B), followed by the ASCII message content, terminating with End Block (0x1C) and Carriage Return (0x0D). The receiver must reply with an acknowledgment message (ACK) within a strict hardware timeout—typically 5 seconds—or the instrument flags a hardware transmission fault and halts specimen processing.

In high-volume hospital labs processing 10,000+ specimens daily, a standard synchronous TCP server causes thread exhaustion. Below is a production ASP.NET Core background service utilizing asynchronous System.IO.Pipelines for zero-allocation MLLP parsing and immediate ACK generation.

MllpSocketListener.cs
csharp
public sealed class MllpSocketListener : BackgroundService
{
    private const byte StartBlock = 0x0B;
    private const byte EndBlock = 0x1C;
    private const byte CarriageReturn = 0x0D;
    private readonly TcpListener _listener = new(IPAddress.Any, 2575);
    private readonly ILogger<MllpSocketListener> _logger;
    private readonly ChannelWriter<Hl7MessagePayload> _inboundQueue;

    public MllpSocketListener(
        ChannelWriter<Hl7MessagePayload> inboundQueue,
        ILogger<MllpSocketListener> logger)
    {
        _inboundQueue = inboundQueue;
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _listener.Start();
        _logger.LogInformation("MLLP Listener running on port 2575");

        while (!stoppingToken.IsCancellationRequested)
        {
            var client = await _listener.AcceptTcpClientAsync(stoppingToken);
            _ = ProcessClientAsync(client, stoppingToken);
        }
    }

    private async Task ProcessClientAsync(TcpClient client, CancellationToken ct)
    {
        using (client)
        await using (var stream = client.GetStream())
        {
            var pipeReader = PipeReader.Create(stream);
            while (!ct.IsCancellationRequested)
            {
                var result = await pipeReader.ReadAsync(ct);
                var buffer = result.Buffer;

                while (TryExtractMllpMessage(ref buffer, out var hl7Raw))
                {
                    // Generate and write immediate ACK to satisfy hardware timeout
                    var ackBytes = GenerateHl7Ack(hl7Raw);
                    await stream.WriteAsync(ackBytes, ct);

                    // Enqueue raw payload for asynchronous FHIR transformation
                    await _inboundQueue.WriteAsync(new Hl7MessagePayload(hl7Raw), ct);
                }

                pipeReader.AdvanceTo(buffer.Start, buffer.End);
                if (result.IsCompleted) break;
            }
        }
    }
}
Asynchronous MLLP frame parser with zero-allocation byte buffers and immediate ACK reply.

3. Transforming HL7 v2 Observations to FHIR R4 JSON

Once the MLLP frame is acknowledged and persisted to an in-memory queue or message broker (RabbitMQ/Kafka), the transformation engine maps clinical entities. An HL7 ORU_R01 (Observation Result Unsolicited) message contains multiple OBX segments representing individual lab tests (e.g., Hemoglobin, Platelet Count, Potassium).

Each OBX segment must map to a FHIR Observation resource with normalized terminology. Below is a TypeScript/Node transformation snippet showing how local analyzer codes are dynamically mapped to LOINC standards and validated.

fhirObservationMapper.ts
typescript
import { Observation, Coding } from 'fhir/r4';

interface ObxSegment {
  setId: string;
  valueType: 'NM' | 'ST' | 'TX'; // Numeric, String, Text
  identifier: string;            // e.g. "HGB^Hemoglobin^LOCAL"
  value: string;
  units: string;
  referenceRange: string;
  abnormalFlags: string;
  status: string;
}

export function mapObxToFhirObservation(
  patientId: string,
  encounterId: string,
  obx: ObxSegment,
  loincCode: string,
  loincDisplay: string
): Observation {
  return {
    resourceType: 'Observation',
    status: 'final',
    category: [
      {
        coding: [
          {
            system: 'http://terminology.hl7.org/CodeSystem/observation-category',
            code: 'laboratory',
            display: 'Laboratory',
          },
        ],
      },
    ],
    code: {
      coding: [
        {
          system: 'http://loinc.org',
          code: loincCode,
          display: loincDisplay,
        },
        {
          system: 'urn:dsf:analyzer:local',
          code: obx.identifier.split('^')[0],
          display: obx.identifier.split('^')[1] || 'Local Code',
        },
      ],
      text: loincDisplay,
    },
    subject: {
      reference: `Patient/${patientId}`,
    },
    encounter: {
      reference: `Encounter/${encounterId}`,
    },
    effectiveDateTime: new Date().toISOString(),
    valueQuantity: obx.valueType === 'NM' ? {
      value: parseFloat(obx.value),
      unit: obx.units,
      system: 'http://unitsofmeasure.org',
      code: obx.units,
    } : undefined,
    valueString: obx.valueType !== 'NM' ? obx.value : undefined,
    referenceRange: obx.referenceRange ? [
      {
        text: obx.referenceRange,
      },
    ] : undefined,
  };
}
Mapping HL7 v2 OBX segments to standard FHIR R4 Observation resource with LOINC coding.

4. SMART on FHIR Security & Clinical Verification

Exposing clinical APIs demands strict zero-trust authentication. The SMART on FHIR profile specifies OAuth 2.0 with asymmetric JSON Web Key Sets (JWKS), PKCE for client applications, and scopes restricted to individual patient or user clinical contexts.

In DSF Hospital Suite, the FHIR API gateway enforces token verification at the reverse proxy layer, auditing all read/write accesses to an immutable, append-only security log for HIPAA and ISO 27001 compliance. Any attempt to query resources outside the authenticated clinician’s ward assignment results in an HTTP 403 Forbidden with security telemetry logging.

Zero-Egress Security Invariant

Diagnostic lab results contain sensitive Protected Health Information (PHI). All MLLP socket listeners and FHIR transformation workers operate strictly within the hospital isolated VLAN. External cloud syncing occurs solely through authenticated mTLS egress proxies.

Explore Related DSF Engineering Solutions & Products

Authoritative Standards & External References