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
Related Articles
Dive deeper into FHIR resource operations with these hands-on tutorials:
- FHIR Programming using Java HAPI - Creating FHIR Resources - Step-by-step resource creation
- FHIR Programming using Java HAPI - Reading FHIR Resources - Retrieving and parsing resources
- FHIR Programming using Java HAPI - Updating FHIR Resources - Modifying existing resources
- FHIR Programming using .NET - Creating FHIR Resources - .NET equivalent examples
- Coded Vocabularies in Health Informatics - Understanding LOINC, SNOMED CT, and other code systems