Qt & QML Development
2026-08-07
11 minutes reading

HL7 FHIR in Qt: Building Healthcare Apps with C++ and QML

Łukasz Kosiński
Łukasz Kosiński Chief Executive Officer

HL7 FHIR gives healthcare systems a standardized way to exchange data. Qt gives engineering teams a mature C++ framework for building native applications across desktop and mobile platforms.

Putting the two together sounds straightforward. In practice, the difficult part sits in the middle.

A FHIR server can expose Patient, Observation, Appointment, Location, Encounter, and many other resources through a REST API. A Qt application still needs to convert those resources into useful C++ objects, handle network communication, resolve references, process search results, and expose exactly the right data to Qt Widgets or QML.

At Somco Software, we do not think that integration layer should be rebuilt from scratch for every healthcare project. That is why we created Somco Software FHIR lib : our internal Qt/C++ foundation for bringing FHIR data into native applications in a way that fits naturally into a maintainable Qt architecture.

What is HL7 FHIR?

HL7 (Health Level Seven) is an international standards organization that develops specifications for exchanging, integrating, and managing electronic healthcare information.

FHIR (Fast Healthcare Interoperability Resources) is the HL7 standard for exchanging healthcare information electronically. Its core building block is the resource : a structured representation of a healthcare or administrative concept such as Patient, Observation, Appointment, Location, or Encounter.

FHIR defines standardized resource structures together with RESTful interactions, allowing healthcare systems to create, read, search, update, and exchange resources using familiar HTTP-based mechanisms.

What FHIR does not define is how those resources should fit into the internal architecture of a native Qt/C++ application.

Why Qt for FHIR-based healthcare applications?

Qt is a strong fit when healthcare software needs to remain a native application rather than becoming another browser-based front end.

For medical software, choosing Qt may also help reduce the complexity of the overall technology stack and simplify the management of third-party and SOUP dependencies. We discuss these considerations in more detail in the video below.

[Osadzone https://www.youtube.com/watch?v=xsOY6RMhea8]

Qt provides a C++ application stack that can target Windows, Linux, macOS, Android, and iOS, while supporting both traditional Qt Widgets interfaces and Qt Quick/QML. Qt also provides first-class mechanisms for integrating QML interfaces with C++ application logic .

Somco Software FHIR lib is designed to support both Qt 5 and Qt 6 , with applications built using Qt Widgets or Qt Quick/QML .

The real question, however, is not whether Qt can send an HTTP request. It can.

The more important question is: How should a large FHIR data model fit into a maintainable Qt application?

See our Qt expertise in medical device

FHIR integration is only one part of building reliable healthcare software. See how our Qt and C++ engineers helped Bio-Rad develop software for the PCR|ONE molecular diagnostics platform.

Read the Bio-Rad case study

The missing layer between FHIR and Qt

Of course it is entirely possible to integrate a FHIR server manually. A developer could construct a request, call an endpoint, receive JSON, inspect resourceType, extract the required properties, convert dates and enumerations, handle missing values, serialize changes back to JSON, and repeat the entire process for the next FHIR resource.

For a proof of concept, that might be acceptable. For a serious application, we believe it is the wrong abstraction.

FHIR is much more than a handful of JSON objects. Resources contain nested structures, references, cardinalities, search parameters, extensions, profiles, and relationships with other resources.

Hand-writing the mechanical mapping for every resource creates exactly the kind of repetitive integration code that becomes expensive to maintain later. Our approach is different: generate as much of the mechanical FHIR API layer as possible, then isolate it behind an application-oriented Qt/C++ layer.

From a FHIR API to strongly typed Qt/C++ classes

The current Somco Software demonstration targets a HAPI FHIR R4 server .

Its OpenAPI description uses OpenAPI 3.0.1 , and the generated Qt/C++ layer contains strongly typed classes representing FHIR resources and API operations.

HAPI FHIR can expose OpenAPI documentation generated from information including the server's CapabilityStatement, while OpenAPI Generator provides a cpp-qt-client generator specifically for producing Qt C++ client libraries.

Conceptually, the architecture looks like this:

Conceptually architecture

The generated layer contains types such as:

FhirPatient
FhirAppointment
FhirLocation

FhirPatientApi
FhirAppointmentApi
FhirLocationApi

This is already a significant improvement over manually parsing every response and constructing every REST operation.

But generated classes are only the first half of the solution.

Generated code is only the beginning

This is where we take a fairly strong position. Generated API code should not become the application architecture.

A generator may produce hundreds of useful resource and API classes. That does not mean every controller, screen, dialog, and business service should depend directly on FhirPatient, FhirAppointment, or whatever representation a particular generator produces. Somco Software FHIR lib adds another boundary.

For example, the application-facing Patient model in our demonstration is intentionally simple:

class Patient
{
public:
    explicit Patient(const QString &id);

    QString id() const;

    QString name() const;
    void setName(const QString &name);

    QString familyName() const;
    void setFamilyName(const QString &familyName);

    QDate birthDate() const;
    void setBirthDate(const QDate &birthDate);

    QString gender() const;
    void setGender(const QString &gender);

private:
    QString m_id;
    QString m_name;
    QString m_familyName;
    QDate m_birthDate;
    QString m_gender;
};

It uses familiar Qt types such as QString and QDate.

  • It does not need to know how a server serializes a FHIR resource.

  • It does not need to know how the OpenAPI client performs an HTTP request.

  • And it does not need to expose every element that exists in the full FHIR Patient definition.

The FHIR representation is converted at the integration boundary:

auto newPatient =
    QSharedPointer<Patient>::create(patient.getId());

const auto &name = patient.getName().value(0);

if (!name->getGiven().isEmpty())
    newPatient->setName(name->getGiven().first());

newPatient->setFamilyName(name->getFamily());

newPatient->setBirthDate(
    QDate::fromString(
        patient.getBirthDate(),
        Qt::ISODate
    )
);

newPatient->setGender(
    capitalize(patient.getGender())
);

This separation gives us control over where FHIR ends and the application begins . A change in the generated API layer should not automatically become a change in the user interface or business logic.

Working with FHIR resources in C++

The same architecture works in the opposite direction when the application needs to create resources.

Consider adding a patient.

In our current implementation, the integration layer creates a strongly typed FhirPatient:

FhirPatient patient;
patient.setResourceType("Patient");

QSharedPointer<FhirHumanName> humanName(
    new FhirHumanName
);

humanName->setGiven({name});
humanName->setFamily(familyName);

patient.setName({humanName});
patient.setGender(gender.toLower());
patient.setBirthDate(
    birthdayDate.toString(Qt::ISODate)
);

The resource can then be serialized and passed to the generated API client:

FhirObject obj;
obj.fromJsonObject(patient.asJsonObject());

m_patientApi->patientPost(obj);

The application code remains firmly in the Qt/C++ world.

QString, QDate, QSharedPointer, Qt signals, and regular C++ models remain part of the architecture while the FHIR-specific layer handles the healthcare representation and API contract.

The current demo covers retrieval, creation, and deletion for Patient, Location, and Appointment resources; update operations are outside the scope of this example.

FHIR references in practice: appointments, patients, and locations

FHIR becomes more interesting when resources start referring to each other.

An Appointment, for example, is not just an independent object containing a few strings.

It can reference a Patient. It can reference a Location.

FHIR represents these relationships through the reference type, including relative references such as:

or:

Our integration layer creates those relationships explicitly.

For the patient:

auto reference =
    QSharedPointer<FhirReference>::create();

reference->setReference(
    "Patient/" + patient->id()
);

And for the location:

auto reference =
    QSharedPointer<FhirReference>::create();

reference->setReference(
    "Location/" + location->id()
);

The references are then assigned to the appointment participants. This reflects the FHIR R4 model, where an Appointment location can be represented by a participant referencing a Location.

When an appointment is loaded from the server, the opposite process happens.

The integration layer reads the reference:

const QStringList parts =
    actor->getReference().split('/');

and resolves it back to an application object:

if (type == "Location") {
    newAppointment->setLocation(
        m_dataHelper.getLocation(id)
    );
} else if (type == "Patient") {
    newAppointment->setPatient(
        m_dataHelper.getPatient(id)
    );
}

That is a small piece of code, but architecturally it says a lot. The FHIR layer understands FHIR relationships . The application works with patients, locations, and appointments. The QML interface should not be responsible for resolving Patient/{id} references.

Loading and searching FHIR resources

Another detail that tends to disappear from simple FHIR tutorials is resource volume. A demonstration with five patients is easy. A real system may not be.

Our demo therefore does not treat resource loading as a single oversized GET /Patient. In the current HAPI FHIR-based implementation, the loading strategy combines standard FHIR search-result controls such as count and elements with implementation-specific pagination behavior used by the demo. The current code also uses _offset as part of that HAPI-based loading strategy.

For patients, the application requests selected elements:

id
name
birthDate
gender

rather than requiring every available property of every Patient resource.

Conceptually, part of that request looks like:

GET /Patient
    ?_count=100
    &_elements=id,name,birthDate,gender

FHIR R4 defines count and elements as standard search-result parameters, while servers determine which search capabilities they actually support. The FHIR specification also returns search results as Bundle resources, so production pagination strategies should be aligned with the behavior and capabilities of the target server.

The current loader works in chunks of 100 resources and continues requesting data until the expected set has been loaded.

The same general approach is used for Location and Appointment.

Keeping that loading strategy below the UI means the presentation layer does not need to know which FHIR search controls or server-specific paging mechanisms are required to obtain its data.

From FHIR to QML

Once data crosses the integration boundary, the Qt Quick side becomes surprisingly ordinary. And that is a good thing.

The appointment screen in our demonstration works with an application model:

ListView {
    model: AppointmentController.model

    delegate: Rectangle {
        Text {
            text: model.startTime
        }

        Text {
            text: model.endTime
        }

        Text {
            text: model.patient
        }

        Text {
            text: model.location
        }
    }
}

This follows a pattern Qt explicitly supports: QML can provide the presentation layer while C++ provides application logic and data models. ( Qt: QML and C++ Integration)

The QML view does not need to parse a FHIR Bundle, construct REST requests, or traverse FHIR references. It simply consumes the application model prepared by the layers below it.

The same integration architecture can sit underneath a Qt Widgets front end when a traditional desktop interface is the better fit.

Somco Software FHIR lib in practice

We built an internal application specifically to exercise the integration using real FHIR resource types instead of stopping at generated classes. The current demo works with Patient, Appointment, and Location resources through a native Qt Quick interface.

Patient view

Patient resources loaded through Somco Software FHIR lib and presented in a native Qt Quick interface.

The Patient view displays application-level fields such as first name, family name, birth date, and gender.

Behind that simple view is the full flow:

FHIR Patient

FHIR complexity should not automatically become UI complexity.

Appointment view

FHIR Appointment data with resolved Patient and Location references in the Somco Software demonstration application.

Appointments are a more interesting example because several resources meet in one workflow.

The UI presents start time, end time, Patient, Location, and application status while the FHIR layer deals with resource references and serialization underneath.

It is a good example of why we prefer strongly typed application models over moving raw JSON through the UI stack.

Location view

FHIR Location resources mapped into application-oriented C++ models and displayed with Qt Quick.

Locations follow exactly the same architectural boundary as Patients and Appointments: the FHIR-specific representation remains in the integration layer, while the UI consumes an application-oriented model.

Simple boundaries scale better than clever shortcuts.

What code generation does not solve

Code generation solves a substantial amount of repetitive API work. It does not magically make a healthcare application production-ready.

A production deployment may still require project-specific decisions around authentication and authorization, FHIR profiles, validation rules, server capabilities, security, error handling, and the particular Implementation Guides used by the target healthcare ecosystem.

Somco Software FHIR lib does not try to pretend those concerns disappear.

Instead, it gives us a proven Qt/C++ foundation on top of which project-specific healthcare requirements can be implemented . That distinction is important.

How Somco Software FHIR lib speeds up development

The obvious benefit is less boilerplate. The more important benefit is less repeated architectural work.

A team starting a native FHIR integration from scratch needs to decide how to represent FHIR resources in C++, communicate asynchronously with the server, handle references between resources, expose data to QML or Qt Widgets, and separate generated code from product code.

Somco Software FHIR lib gives our projects an existing foundation for those decisions instead of forcing the same integration architecture to be designed again for each implementation.

Somco Software FHIR lib is a privately maintained internal engineering library that we use as a reusable foundation for client projects requiring FHIR integration in Qt applications.

That does not mean every client receives exactly the same implementation. Quite the opposite.

The FHIR server may differ. The required resources may differ. Authentication may differ. Profiles may differ. The UI certainly will. What remains reusable is the engineering approach.

When a project needs another FHIR resource, we would rather start the discussion with:

How should this resource behave in the application?

than:

How do we build the FHIR-to-C++ integration layer again?

That is where the real development-time advantage appears.

Where this architecture makes sense

FHIR and Qt are an especially strong combination when a product needs both healthcare interoperability and native software capabilities .

This can include clinical desktop systems, diagnostic or laboratory interfaces, scheduling applications, device-related software, and other native healthcare products that need to exchange data through FHIR.

But there is one scenario we find particularly interesting. An organization already has a mature Qt/C++ product. It works. Users know it. The engineering team understands it. Years of product logic may already exist inside that codebase.

Then a new requirement appears: the application now needs to participate in a FHIR-based healthcare ecosystem.

Rewriting a mature native product around a different application stack solely because FHIR uses HTTP is often unnecessary. FHIR defines standardized resource structures and RESTful interactions; it does not require the consuming application to run in a browser.

A native Qt application can remain a native Qt application while gaining a standards-based healthcare interoperability layer.

That is exactly the kind of problem where a reusable FHIR/Qt foundation becomes valuable.

Build the healthcare product, not another integration layer

FHIR and Qt solve two different problems. FHIR standardizes how healthcare information can be represented and exchanged. Qt provides the C++ application framework needed to build native software across desktop and mobile platforms. The engineering challenge is the layer between them.

Our approach at Somco Software is straightforward: generate the mechanical FHIR API layer, keep it behind an application-oriented C++ boundary, and expose clean models to Qt Widgets or QML.

Somco Software FHIR lib gives us a reusable starting point for doing exactly that. Our current demonstration targets FHIR R4 and works with Patient, Appointment, and Location resources. The more important idea, however, is the architecture behind those examples: when a healthcare project needs FHIR inside a Qt application, the integration does not need to begin from an empty repository.

We want to begin with a working foundation. Then spend the engineering time where it actually creates value: on the healthcare product itself.

Contact us

Lukas Kosiński

Lukas Kosiński

CEO, Somco Software

We work with Qt and embedded software daily. I've been awarded the Qt Champion title three times.
Messages from this form land directly in my inbox. I read and answer them, usually within one business day.

Connect with me on LinkedIn

The administrator of the personal data is Somco Software sp. z o.o., 13 Gen. Ottokara Brzoza-Brzeziny St., 05-220 Zielonka, KRS: 855688. The personal data are processed in order to answer the question contained in the contact form. More information, including a description of data subjects rights, is available in the information clause .