Working with FHIR Resources

Section 6 of 18
33% complete

Creating Patient Resources

The Patient resource is one of the most commonly used FHIR resources, serving as the foundation for most clinical data. A well-constructed patient includes identifiers (like MRN), demographics (name, gender, birth date), contact information, and administrative details. HAPI FHIR provides a fluent API with method chaining that makes resource construction readable and maintainable. Always include proper identifiers and use standardized code systems for interoperability.

Here is how to create a detailed patient:

import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
import java.util.Date;

public class PatientCreationExample {

    public static Patient createDetailedPatient() {
        Patient patient = new Patient();

        // Add identifier (MRN - Medical Record Number)
        patient.addIdentifier()
            .setSystem("http://hospital.org/mrn")
            .setValue("MRN-123456")
            .setUse(Identifier.IdentifierUse.OFFICIAL);

        // Add name
        HumanName name = patient.addName();
        name.setUse(HumanName.NameUse.OFFICIAL)
            .setFamily("Johnson")
            .addGiven("Robert")
            .addGiven("James")
            .addPrefix("Mr.");

        // Add nickname
        patient.addName()
            .setUse(HumanName.NameUse.NICKNAME)
            .addGiven("Bob");

        // Set gender
        patient.setGender(AdministrativeGender.MALE);

        // Set birth date
        patient.setBirthDateElement(new DateType("1980-06-15"));

        // Add address
        Address address = patient.addAddress();
        address.setUse(Address.AddressUse.HOME)
            .setType(Address.AddressType.PHYSICAL)
            .addLine("123 Main Street")
            .addLine("Apt 4B")
            .setCity("Springfield")
            .setState("IL")
            .setPostalCode("62701")
            .setCountry("USA");

        // Add phone
        patient.addTelecom()
            .setSystem(ContactPoint.ContactPointSystem.PHONE)
            .setValue("+1-555-123-4567")
            .setUse(ContactPoint.ContactPointUse.HOME);

        // Add email
        patient.addTelecom()
            .setSystem(ContactPoint.ContactPointSystem.EMAIL)
            .setValue("[email protected]")
            .setUse(ContactPoint.ContactPointUse.WORK);

        // Set active status
        patient.setActive(true);

        return patient;
    }
}

Creating Observation Resources

Observations record clinical measurements and findings, from vital signs to lab results. Each observation requires a status (preliminary, final, amended), a code identifying what was measured (typically using LOINC), and a value with appropriate units. For complex measurements like blood pressure, use component elements to group related values within a single observation. Always link observations to their subject (patient) and consider adding encounter context for clinical workflows.

Blood Pressure Observation

Blood pressure is a compound measurement requiring both systolic and diastolic values. Rather than creating separate observations, FHIR recommends using a panel observation with components. This approach keeps related measurements together and follows the pattern used by major implementation guides like US Core.

import org.hl7.fhir.r4.model.*;
import java.util.Date;

public class ObservationCreationExample {

    public static Observation createBloodPressureObservation() {
        Observation observation = new Observation();

        // Set status
        observation.setStatus(Observation.ObservationStatus.FINAL);

        // Set category
        observation.addCategory()
            .addCoding()
            .setSystem("http://terminology.hl7.org/CodeSystem/observation-category")
            .setCode("vital-signs")
            .setDisplay("Vital Signs");

        // Set code (LOINC for blood pressure)
        observation.setCode(new CodeableConcept()
            .addCoding()
            .setSystem("http://loinc.org")
            .setCode("85354-9")
            .setDisplay("Blood pressure panel"));

        // Set subject (patient reference)
        observation.setSubject(new Reference("Patient/example"));

        // Set effective date/time
        observation.setEffective(new DateTimeType(new Date()));

        // Add systolic component
        Observation.ObservationComponentComponent systolic =
            observation.addComponent();
        systolic.setCode(new CodeableConcept()
            .addCoding()
            .setSystem("http://loinc.org")
            .setCode("8480-6")
            .setDisplay("Systolic blood pressure"));
        systolic.setValue(new Quantity()
            .setValue(120)
            .setUnit("mmHg")
            .setSystem("http://unitsofmeasure.org")
            .setCode("mm[Hg]"));

        // Add diastolic component
        Observation.ObservationComponentComponent diastolic =
            observation.addComponent();
        diastolic.setCode(new CodeableConcept()
            .addCoding()
            .setSystem("http://loinc.org")
            .setCode("8462-4")
            .setDisplay("Diastolic blood pressure"));
        diastolic.setValue(new Quantity()
            .setValue(80)
            .setUnit("mmHg")
            .setSystem("http://unitsofmeasure.org")
            .setCode("mm[Hg]"));

        return observation;
    }
}

Lab Result with Reference Range

Lab results often include reference ranges to indicate normal values and interpretations to flag abnormal results. Reference ranges help clinicians quickly assess whether a result requires attention. The interpretation codes (Normal, High, Low, Critical) follow HL7 terminology and are essential for clinical decision support systems and alerting workflows.

public static Observation createLabResult() {
    Observation observation = new Observation();

    observation.setStatus(Observation.ObservationStatus.FINAL);

    // Lab category
    observation.addCategory()
        .addCoding()
        .setSystem("http://terminology.hl7.org/CodeSystem/observation-category")
        .setCode("laboratory")
        .setDisplay("Laboratory");

    // Glucose test
    observation.setCode(new CodeableConcept()
        .addCoding()
        .setSystem("http://loinc.org")
        .setCode("2339-0")
        .setDisplay("Glucose [Mass/volume] in Blood"));

    observation.setSubject(new Reference("Patient/example"));
    observation.setEffective(new DateTimeType(new Date()));

    // Result value
    observation.setValue(new Quantity()
        .setValue(95)
        .setUnit("mg/dL")
        .setSystem("http://unitsofmeasure.org")
        .setCode("mg/dL"));

    // Reference range
    observation.addReferenceRange()
        .setLow(new Quantity().setValue(70).setUnit("mg/dL"))
        .setHigh(new Quantity().setValue(100).setUnit("mg/dL"))
        .setText("Normal Range");

    // Interpretation
    observation.addInterpretation()
        .addCoding()
        .setSystem("http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation")
        .setCode("N")
        .setDisplay("Normal");

    return observation;
}

Common Resource Patterns

Adding Identifiers

Every resource can have identifiers. Identifiers are business identifiers assigned by external systems, such as Medical Record Numbers (MRNs), Social Security Numbers, or insurance member IDs. They differ from FHIR resource IDs which are server-assigned. Use the system URI to specify the namespace and include the use element to indicate whether the identifier is official, usual, or temporary.

resource.addIdentifier()
    .setSystem("http://your-organization.org/identifier-type")
    .setValue("unique-value")
    .setUse(Identifier.IdentifierUse.OFFICIAL);

Creating References

Link resources together using references. References create relationships between FHIR resources, such as linking an observation to its patient or a medication request to its prescriber. You can reference by ID (when resources are on the same server), by identifier (for cross-server references), or include a display text for human readability. Choose the reference style based on your integration architecture.

// By ID
new Reference("Patient/123")

// By ID with display
new Reference("Patient/123").setDisplay("John Smith")

// By identifier
new Reference().setIdentifier(
    new Identifier()
        .setSystem("http://hospital.org/mrn")
        .setValue("MRN-12345")
)

Using CodeableConcepts

Represent coded values with multiple coding systems using CodeableConcept. Healthcare data often needs to be expressed in multiple terminologies (SNOMED CT for clinical precision, ICD-10 for billing). CodeableConcept allows multiple codings for the same concept plus a human-readable text element. This flexibility supports interoperability across systems that may use different code systems for the same clinical concept.

CodeableConcept concept = new CodeableConcept()
    .addCoding()
        .setSystem("http://snomed.info/sct")
        .setCode("38341003")
        .setDisplay("Hypertensive disorder")
    .addCoding()
        .setSystem("http://hl7.org/fhir/sid/icd-10")
        .setCode("I10")
        .setDisplay("Essential hypertension");
concept.setText("High Blood Pressure");

Congratulations!

You’ve completed the FHIR fundamentals tutorial! You now understand:

  • What FHIR is and its advantages
  • FHIR version history and compatibility
  • Core architecture concepts
  • Development environment setup
  • HAPI FHIR library basics
  • Creating clinical resources

Next Steps:

  • Explore FHIR RESTful operations (CRUD)
  • Learn about search parameters
  • Understand validation and profiles
  • Build integration solutions with Apache Camel

Dive deeper into FHIR resource operations with these hands-on tutorials:

Quiz: Working with FHIR Resources

Question 1 of 5

Which method adds a new name to a Patient resource?