Manipulating FHIR Resource: HAPI FHIR API
จัดการ FHIR Resource ผ่าน Java Programming API: HAPI FHIR
ในตอนนี้จะเป็นการจัดการ FHIR resource ด้วย programming API ใน Java platform
HAPI
HAPI (HL7 API) project เป็น open-source implementation ของ HL7 specification ใน Java platform ตั้งแต่ HL7 ยังเป็นรุ่น 2.x เริ่มต้นโดย University Health Network (UHN) (https://www.uhn.ca/) ซึ่งเป็นกลุ่มเครือข่ายโรงพยาบาลขนาดใหญ่หลายแห่งที่มีการสอนบุคลากรทางการแพทย์ในระดับคลินิก (teaching hospital) ในเมือง Toronto, ประเทศ Canada
โดยมี James Agnew ซึ่งเป็น Lead Architect ของ Centre for Global eHealth Innovation ของ UHN และหนึ่งในสมาชิกของ FHIR Core Team เป็น project leader ของ HAPI project
HAPI FHIR (https://hapifhir.io) เป็น library ที่เป็น open-source implementation ของมาตรฐาน HL7 FHIR บน Java platform
HAPI FHIR รุ่นล่าสุดคือรุ่น 4.2.0 สนับสนุน JDK ตั้งแต่รุ่น JDK8 ขึ้นมา และสนับสนุน FHIR ตั้งแต่รุ่น DSTU2, DSTU3, R4 (HL7 FHIR รุ่น DSTU3 เปลี่ยนชื่อเป็น STU3 ในเวลาต่อมา แต่ใน HAPI ยังใช้ DSTU3 อยู่ตามเดิม เพื่อให้ code เดิมยังใช้งานต่อได้)
HAPI FHIR มี class library สำหรับ resource และ data type ทุกประเภทที่กำหนดโดยข้อกำหนด FHIR ตัวอย่างเช่น class สำหรับ Patient resource หากดู JavaDoc จะเห็น getters และ setters สำหรับ properties ต่างๆ ที่ประกอบขึ้นเป็น Patient resource
FHIR Context
ในการใช้งาน object ต่างๆ ที่สร้างขึ้นจาก class library นี้ จำเป็นต้องสร้าง FhirContext
ขึ้นมาก่อน (JavaDoc) FhirContext
เป็นจุดเริ่มต้นสำหรับการใช้งาน HAPI และขึ้นอยู่กับรุ่นของ FHIR ที่ต้องการใช้งานในแอป
// Create a context for DSTU3
FhirContext ctx = FhirContext.forDstu3();// or create a context for R4
FhirContext ctx = FhirContext.forR4();
FHIRContext
เป็น object ที่ใช้ทรัพยากร จึงควรสร้าง object ไว้ครั้งเดียวและเก็บไว้ใช้งานตลอดทั้งแอปจนกว่าจะปิดแอป
HAPI FHIR Modules
Modules ที่สำคัญใน HAPI FHIR library สำหรับการใช้งาน ได้แก่
- Core Library:
hapi-fhir-base
เป็น core HAPI FHIR library จำเป็นเสมอสำหรับการใช้งาน framework (JavaDoc) - Structure: เป็น library ของ model classes ต่างๆ จาก FHIR resources และ data types ขึ้นอยู่กับรุ่นของ FHIR ที่ต้องการสนับสนุน สำหรับรุ่น R4 คือ
hapi-fhir-structures-r4
(JavaDoc) - Client Framework:
hapi-fhir-client
เป็น library ของ core FHIR client framework จำเป็นสำหรับการใช้งานฟังก์ชั่นต่างๆ ของ client ใน HAPI (JavaDoc) - Validation: เป็น library ของ FHIR Profile Validator ใช้เพื่อตรวจสอบความถูกต้องของข้อมูล Resources กับ FHIR Profiles
- Server: สำหรับใช้พัฒนา FHIR-compliant server กับ data storage ที่มีอยู่
รายละเอียดของแต่ละ modules ดูได้จากที่นี่
Importing HAPI FHIR
วิธีที่ง่ายที่สุดในการใช้ HAPI FHIR คือการใช้ระบบ build system ที่จัดการ dependency โดยอัตโนมัติ ระบบจะช่วยดาวน์โหลดและเพิ่ม library ที่ต้องการใน classpath ในที่นี้จะใช้ระบบของ Apache Maven
ใน Maven project file (pom.xml) ต้องมี HAPI FHIR core JAR และ Structure JAR (อย่างน้อย 1 รุ่นที่ต้องการ)
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-r4</artifactId>
<version>4.2.0</version>
</dependency>
หากต้องการใช้งานฟังก์ชั่นของ client ใน HAPI เพิ่ม module client รวมเข้าไป
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-client</artifactId>
<version>4.2.0</version>
</dependency>
ต่อไปจะอ่านข้อมูลเดิมที่เคยสร้างไว้ด้วย clinFHIR และเก็บไว้ที่ Public test server ของ HAPI (http://hapi.fhir.org/baseR4)
Reading FHIR Resource with HAPI
สร้าง FHIR Context และ Generic Client สำหรับอ่านข้อมูล resource จาก server ที่เก็บข้อมูล resource
FhirContext ctx = FhirContext.forR4(); IGenericClient client = ctx.newRestfulGenericClient("http://hapi.fhir.org/baseR4");
Patient Resource
อ่านข้อมูล Patient resource, Id 921009 เก็บไว้ใน Patient
object สำหรับใช้งาน
Patient patient = client.read().resource(Patient.class).withId("921009").execute();
แสดงผลข้อมูล Patient resource ใน data element ที่ต้องการ
System.out.printf("NAME: %s%n", patient.getNameFirstRep().getNameAsSingleString());System.out.printf("BIRTHDATE: %tF%n", patient.getBirthDate());
โมเดลข้อมูล FHIR นั้นสมบูรณ์เพียงพอที่จะรองรับกรณีใช้งานทั่วไป แต่บางครั้งความสมบูรณ์นั้นเพิ่มความซับซ้อน ตัวอย่างเช่น ผู้ป่วยอาจมีได้หลายชื่อ (ชื่อที่เป็นทางการ ชื่อเล่น ฯลฯ ) element name
ใน Patient resource จึงมี cardinality เป็น 0..* ของ data type HumanName
หากใช้ method getName()
(JavaDoc) ใน HAPI FHIR จะส่งค่ากลับมาเป็น List<HumanName>
แต่ HAPI FHIR มี method ที่ช่วยอำนวยความสะดวกในการส่งค่า HumanName
แรกใน element name
คือ getNameFirstRep()
(JavaDoc)
Condition Resource
แสดง Problem list จาก list ของ object Condition
ที่มี subject=921009
Bundle conditionBundle = client.search().forResource(Condition.class)
.where(Condition.SUBJECT.hasId("921009"))
.returnBundle(Bundle.class).execute();if(conditionBundle.hasEntry()) {
System.out.println("PROBLEM LIST:"); List<BundleEntryComponent> entries = conditionBundle.getEntry(); int i = 1;
for (BundleEntryComponent ent : entries) {
Condition c = (Condition)ent.getResource(); System.out.printf("%3d. %-40s %-12s %n",
i++,
c.getCode().getText(),
c.getSeverity().getText());
}
}
Method execute()
จะส่งค่ากลับมาเป็น object ชนิดเดียวกับ object ที่เรียก method นี้ ในตัวอย่างแรก withId()
ถูกเรียกจาก method resource(Patient.class)
เมื่อเรียก method execute()
ต่อจึงได้ค่ากลับมาเป็น Patient object ส่วนในตัวอย่างที่สอง returnBundle()
ถูกเรียกจาก method forResource(Condition.class).where(…)
เมื่อเรียก method execute()
ต่อจึงได้ค่ากลับมาเป็น Bundle
object ที่สามารถ cast entry ใน Bundle ไปเป็น Condition
object ได้
(JavaDoc: class Condition
, method execute()
, withId()
, resource()
, forResource()
, returnBundle()
)
Output:
Encounter Resource
ในประเทศไทยอาจจะคุ้นเคยกับคำว่า “visit” สำหรับเรียกการมารับบริการในแต่ละครั้ง แต่ HL7 จะเรียกตรงนี้ว่า “encounter” (https://www.hl7.org/fhir/encounter.html)
ค้นหา Encounter resource ที่มี subject=921009
Bundle encounterBundle = client.search().forResource(Encounter.class)
.where(Encounter.SUBJECT.hasId("921009"))
.returnBundle(Bundle.class).execute();if(encounterBundle.hasEntry()) {
System.out.println("ENCOUNTER LIST:"); List<BundleEntryComponent> entries = encounterBundle.getEntry(); for (BundleEntryComponent ent : entries) {
Encounter e = (Encounter)ent.getResource(); System.out.printf("DATE: %tF TYPE: %-15s PARTICIPANT: %s %n",
e.getPeriod().getStart(),
e.getTypeFirstRep().getText(),
e.getParticipantFirstRep().getIndividual().getDisplay());
}
}
(JavaDoc: class Encounter)
Output:
Full code listing:
หมายเหตุ:
- Java ที่ใช้ demo เป็นรุ่น Java 11 ซึ่งอาจมี syntax หรือ method ที่ไม่เหมือนกับ Java 8