HL7 vs FHIR: Sekilas tentang protocol di dunia HealthTech
Saat saya pertama kali mendengar istilah "HL7" dan "FHIR" dalam konteks proyek migrasi sistem rekam medis, reaksi pertama saya: "Ini pasti mirip ISO 8583 tapi untuk rumah sakit." Ternyata analogi itu cukup akurat — dan menjadi jembatan yang membantu saya memahami ekosistem ini dengan jauh lebih cepat.
Artikel ini saya tulis sebagai starting point yang saya harap ada waktu saya pertama terjun ke healthcare tech: tidak terlalu dangkal, tidak terlalu teoritis — langsung ke inti yang penting bagi seorang Java developer.
Mengapa Interoperabilitas Jadi Masalah Besar?
Bayangkan seorang pasien yang menjalani operasi di Rumah Sakit A, melanjutkan rawat jalan di Klinik B, menebus obat di Apotek C, dan mengklaim asuransi ke BPJS. Empat entitas ini — tanpa standar komunikasi yang sama — tidak bisa berbagi data pasien secara otomatis. Dokter di Klinik B tidak tahu riwayat operasi lengkapnya. Apotek C tidak tahu alergi obatnya. BPJS meminta berkas manual.
Inilah mengapa HL7 International (Health Level Seven) hadir sejak 1987: menyusun standar agar semua sistem kesehatan bisa "berbicara" dalam bahasa yang sama. Mereka menghasilkan dua generasi standar yang kini hidup berdampingan: HL7 v2 dan FHIR.
HL7 v2 — Sang Veteran yang Masih Produktif
HL7 v2 (Health Level Seven Version 2) lahir pada 1987 dan merilis versi terakhirnya (2.9) pada 2019. Usianya hampir empat dekade, namun hingga hari ini ia masih menjalankan jutaan transaksi medis setiap harinya di seluruh dunia — termasuk di banyak rumah sakit Indonesia.
Struktur Pesan HL7 v2
Pesan HL7 v2 adalah teks biasa dengan format pipe-delimited. Setiap baris disebut Segment, setiap kolom dipisahkan dengan karakter |, dan subfield dipisahkan dengan ^.
Anatomi pesan ADT^A04 (Pasien Baru Mendaftar):
-- MSH: Message Header (wajib ada di semua pesan)
MSH|^~\&|SIMRS_BANDUNG|RS_HARAPAN|BPJS_GATEWAY|BPJS_PUSAT|20250622170000||ADT^A04^ADT_A01|MSG-2025-001|P|2.5.1
-- PID: Patient Identification
PID|1||12345678^^^RS_HARAPAN^MR||Ibrahim^Mohamad Yusuf||19850101|M|||Jl. Merdeka No.1^^Bandung^JB^40111^ID
-- PV1: Patient Visit (informasi kunjungan)
PV1|1|O|POLI-UMUM^Poliklinik Umum^RS_HARAPAN||||dr.SANJAYA^Sanjaya^Budi^^^dr.|||MED
-- IN1: Insurance (data BPJS)
IN1|1|BPJS|BPJS|BPJS Kesehatan||||0001987654321
Jenis-Jenis Pesan HL7 v2 yang Sering Ditemui
| Message Type | Nama Event | Trigger |
|---|---|---|
| ADT^A01 | Admit Patient | Pasien rawat inap |
| ADT^A04 | Register Patient | Pendaftaran rawat jalan / IGD |
| ADT^A08 | Update Patient Info | Data demografis berubah |
| ORM^O01 | General Order Message | Order lab / radiologi dari dokter |
| ORU^R01 | Unsolicited Observation | Hasil lab dikirim ke SIMRS |
| MDM^T02 | Medical Document | Dokumen rekam medis / discharge summary |
FHIR — Generasi Baru yang Ramah Developer
FHIR (Fast Healthcare Interoperability Resources, dibaca "fire") adalah standar modern yang dikembangkan HL7 International sejak 2011. Filosofi dasarnya: buat standar kesehatan yang bisa langsung dipakai oleh web developer tanpa perlu belajar 500 halaman spesifikasi terlebih dahulu.
Versi aktif saat ini adalah FHIR R4 (Release 4, 2019), dan Indonesia menjadikannya fondasi platform SATUSEHAT milik Kemenkes.
Konsep Utama: Resources
Di FHIR, semua entitas direpresentasikan sebagai Resource — objek JSON mandiri yang punya struktur standar dan bisa diakses via REST API. Ada 140+ resource dalam FHIR R4, namun Anda cukup menguasai yang sering dipakai:
| Resource | Representasi | Analogi di Banking |
|---|---|---|
| Patient | Data demografis pasien | Customer / Nasabah |
| Encounter | Episode kunjungan / rawat inap | Sesi transaksi / kontrak |
| Observation | Hasil pemeriksaan (lab, vital sign) | Transaction record |
| Condition | Diagnosis / penyakit | Account status / flag |
| MedicationRequest | Resep dokter | Payment instruction |
| Practitioner | Data dokter / tenaga medis | Merchant / counterparty |
| Organization | Rumah sakit / klinik / apotek | Bank / financial institution |
| Bundle | Kumpulan resources (response batch) | Batch file / settlement report |
| DiagnosticReport | Laporan pemeriksaan lengkap | Account statement |
| AllergyIntolerance | Alergi dan intoleransi obat | Customer restriction / blacklist |
Contoh FHIR Resource: Patient (Lengkap)
{
"resourceType": "Patient",
"id": "pat-12345678",
"meta": {
"versionId": "1",
"lastUpdated": "2025-06-22T17:00:00+07:00",
"profile": ["https://fhir.kemkes.go.id/r4/StructureDefinition/Patient"]
},
"identifier": [
{
"use": "official",
"system": "https://fhir.kemkes.go.id/id/nik",
"value": "3273011501850001"
},
{
"use": "local",
"system": "http://rs-harapan.example.id/mrn",
"value": "MRN-2025-12345"
}
],
"name": [
{
"use": "official",
"family": "Ibrahim",
"given": ["Mohamad", "Yusuf"]
}
],
"telecom": [
{ "system": "phone", "value": "+6281234567890", "use": "mobile" }
],
"gender": "male",
"birthDate": "1985-01-01",
"address": [
{
"use": "home",
"line": ["Jl. Merdeka No. 1"],
"city": "Bandung",
"postalCode": "40111",
"country": "ID"
}
]
}
FHIR REST API — Operasi Dasar
Operasi FHIR mengikuti konvensi REST yang sudah familiar bagi setiap backend developer:
-- CREATE: Daftarkan pasien baru
POST /fhir/Patient
-- READ: Ambil data pasien berdasarkan ID
GET /fhir/Patient/pat-12345678
-- UPDATE: Perbarui data lengkap
PUT /fhir/Patient/pat-12345678
-- PATCH: Perbarui sebagian data (JSON Patch)
PATCH /fhir/Patient/pat-12345678
-- SEARCH: Cari dengan query parameters
GET /fhir/Patient?identifier=3273011501850001
GET /fhir/Patient?name=Ibrahim&birthdate=1985-01-01
GET /fhir/Observation?patient=pat-12345678&code=15074-8&_sort=-date
-- BATCH: Kirim beberapa resource sekaligus (via Bundle)
POST /fhir (dengan Bundle berisi multiple resources)Perbandingan Lengkap: HL7 v2 vs FHIR
| Aspek | HL7 v2 | FHIR R4 |
|---|---|---|
| Format Data | Pipe-delimited text | JSON (default), XML, Turtle |
| Transport Protocol | MLLP/TCP (port 2575) | HTTP/HTTPS (REST) |
| Arsitektur | Event-driven messaging | Resource-centric REST API |
| Autentikasi | Network-level (VPN/VNet) | OAuth 2.0 / SMART on FHIR |
| Kemudahan Parsing | Butuh library khusus (HAPI HL7) | Standard JSON parser cukup |
| Query Kemampuan | Terbatas, tidak fleksibel | Search parameters yang powerful |
| Extensibility | Z-segments (tidak standar) | Extension mechanism (tetap valid) |
| Versi | v2.1 s/d v2.9 | DSTU2, STU3, R4, R4B, R5 |
| Status di Indonesia | Legacy — masih dominan di RS lama | Standar SATUSEHAT Kemenkes |
| Cocok untuk | Integrasi sistem lama, real-time event | API modern, mobile apps, analytics |
Implementasi di Spring Boot — Praktis dan Langsung
Setup: HL7 v2 dengan HAPI HL7
// build.gradle
dependencies {
// HAPI HL7 v2 — library de facto untuk HL7 v2 di Java
implementation 'ca.uhn.hapi:hapi-base:2.5.1'
implementation 'ca.uhn.hapi:hapi-structures-v25:2.5.1'
// MLLP transport via Spring Integration atau Apache Camel
implementation 'org.apache.camel.springboot:camel-spring-boot-starter:4.6.0'
implementation 'org.apache.camel.springboot:camel-hl7-starter:4.6.0'
implementation 'org.apache.camel.springboot:camel-mllp-starter:4.6.0'
}
// Listener MLLP — menerima pesan HL7 v2 dari SIMRS
@Component
public class HL7v2MllpRoute extends RouteBuilder {
@Override
public void configure() {
// Terima di port 2575, parse otomatis
from("mllp://0.0.0.0:2575")
.routeId("hl7v2-inbound")
.unmarshal(HL7.hl7()) // parse pipe-delimited → HAPI object
.process(exchange -> {
Message hl7Msg = exchange.getIn().getBody(Message.class);
String msgType = hl7Msg.getName(); // "ADT_A04", "ORM_O01", dll
// Kirim ke Kafka untuk diproses async
exchange.setProperty("msgType", msgType);
})
.choice()
.when(exchangeProperty("msgType").startsWith("ADT"))
.to("kafka:hl7-adt-events")
.when(exchangeProperty("msgType").startsWith("ORU"))
.to("kafka:hl7-lab-results")
.otherwise()
.to("kafka:hl7-other-events")
.end();
}
}
Setup: FHIR R4 dengan HAPI FHIR
// build.gradle
dependencies {
// HAPI FHIR — toolkit FHIR paling lengkap untuk Java
implementation 'ca.uhn.hapi.fhir:hapi-fhir-base:7.4.0'
implementation 'ca.uhn.hapi.fhir:hapi-fhir-structures-r4:7.4.0'
implementation 'ca.uhn.hapi.fhir:hapi-fhir-client:7.4.0'
// Jika ingin run FHIR server sendiri:
implementation 'ca.uhn.hapi.fhir:hapi-fhir-server:7.4.0'
implementation 'ca.uhn.hapi.fhir:hapi-fhir-jpaserver-base:7.4.0'
}
// Service untuk berinteraksi dengan SATUSEHAT API
@Service
public class SatuSehatFhirService {
private final IGenericClient fhirClient;
private final FhirContext fhirContext;
public SatuSehatFhirService() {
// FHIR R4 context — inisialisasi sekali, thread-safe
this.fhirContext = FhirContext.forR4();
// Base URL SATUSEHAT (sandbox)
this.fhirClient = fhirContext.newRestfulGenericClient(
"https://api-satusehat.kemkes.go.id/fhir-r4/v1"
);
// Tambahkan interceptor untuk OAuth 2.0
fhirClient.registerInterceptor(new BearerTokenAuthInterceptor("your-token"));
}
/**
* Kirim data kunjungan pasien ke SATUSEHAT
*/
public MethodOutcome createEncounter(Encounter encounter) {
return fhirClient.create()
.resource(encounter)
.encodedJson()
.execute();
}
/**
* Cari riwayat lab pasien berdasarkan NIK
*/
public Bundle searchLabResults(String nik) {
return fhirClient.search()
.forResource(Observation.class)
.where(Observation.PATIENT.hasChainedProperty(
Patient.IDENTIFIER.exactly().systemAndCode(
"https://fhir.kemkes.go.id/id/nik", nik
)
))
.and(Observation.CATEGORY.exactly().code("laboratory"))
.sort().descending(Observation.DATE)
.count(50)
.returnBundle(Bundle.class)
.execute();
}
}
Pola Hybrid: HL7 v2 → Konversi → FHIR
Inilah pola yang paling sering digunakan dalam proyek nyata. Sistem lama mengirim HL7 v2, kita konversi ke FHIR untuk dilaporkan ke SATUSEHAT atau dikonsumsi sistem modern.
[ SIMRS Lama ] ──MLLP:2575──→ [ Camel MLLP Listener ]
│
▼
[ Kafka: hl7-raw-events ] ←── parse & publish
│
▼
[ HL7→FHIR Transformer Service ]
│
┌──────────────────────┤
▼ ▼
[ HAPI FHIR JPA Server ] [ SATUSEHAT API ]
(internal / on-premise) (laporan Kemenkes)
// HL7 v2 ADT → FHIR Patient (contoh konversi)
@Component
public class HL7v2ToFhirConverter {
public Patient convertPidToFhirPatient(PID pid) throws HL7Exception {
Patient patient = new Patient();
// MRN dari PID-3
String mrn = pid.getPatientIdentifierList(0).getIDNumber().getValue();
patient.addIdentifier()
.setSystem("http://rs.example.id/mrn")
.setValue(mrn);
// Nama dari PID-5: family^given
XPN name = pid.getPatientName(0);
patient.addName()
.setFamily(name.getFamilyName().getSurname().getValue())
.addGiven(name.getGivenName().getValue());
// Gender dari PID-8
String sex = pid.getAdministrativeSex().getValue();
patient.setGender("M".equals(sex)
? Enumerations.AdministrativeGender.MALE
: Enumerations.AdministrativeGender.FEMALE);
// Tanggal lahir dari PID-7
patient.setBirthDateElement(new DateType(
pid.getDateTimeOfBirth().getTime().getValueAsDate()
));
return patient;
}
}
Analogi Banking → HealthTech (Untuk Mempercepat Pemahaman)
Jika Anda datang dari dunia banking seperti saya, tabel mental ini akan sangat membantu:
SATUSEHAT — Konteks Indonesia yang Wajib Dipahami
Sejak 2022, Kementerian Kesehatan mewajibkan seluruh fasilitas kesehatan (faskes) di Indonesia — rumah sakit, puskesmas, klinik, apotek — untuk terhubung ke platform SATUSEHAT. Platform ini menggunakan FHIR R4 sebagai standar datanya.
| Aspek | Detail |
|---|---|
| Base URL Sandbox | https://api-satusehat.kemkes.go.id/fhir-r4/v1 |
| Autentikasi | OAuth 2.0 Client Credentials (client_id + client_secret per faskes) |
| Dokumen Wajib Dikirim | Encounter, Condition (diagnosis), Observation (vital sign + lab), MedicationRequest, Procedure |
| Identitas Pasien | Wajib match ke NIK via https://fhir.kemkes.go.id/id/nik |
| Profil Custom | Kemenkes mendefinisikan StructureDefinition sendiri di atas FHIR R4 standar |
Roadmap Belajar untuk Java Developer
-
1Pahami struktur HL7 v2 secara manual Baca dan parse pesan ADT^A01 dan ORU^R01 menggunakan HAPI HL7. Coba buat MLLP listener sederhana dengan Apache Camel.
-
2Kuasai FHIR R4 resources utama Mulai dari Patient, Encounter, Observation, Condition. Baca spesifikasi di hl7.org/fhir/R4 — lebih readable dari yang Anda bayangkan.
-
3Setup HAPI FHIR JPA Server secara lokal Jalankan via Docker: docker run -p 8080:8080 hapiproject/hapi:latest. Ini memberi Anda sandbox FHIR server lengkap untuk bereksperimen.
-
4Pelajari SMART on FHIR + OAuth 2.0 Framework autentikasi standar untuk FHIR apps. Analoginya: seperti OAuth 2.0 di Open Banking, tapi dengan scope yang spesifik untuk data klinis.
-
5Daftar akun SATUSEHAT developer sandbox Buka platform.satusehat.kemkes.go.id, daftar sebagai developer, dan coba kirim Patient + Encounter ke environment sandbox.
-
6Bangun hybrid pipeline HL7 v2 → FHIR Ini adalah skill yang paling dicari di pasar. Buat proof-of-concept: Camel MLLP listener → Kafka → transformer service → HAPI FHIR server.
Toolkit Esensial: Perbandingan Library
🔧 HL7 v2 (HAPI HL7)
- hapi-base — core library
- hapi-structures-v25 — model v2.5
- camel-hl7 — parser otomatis
- camel-mllp — transport MLLP
- Alternatif: Spring Integration + HL7
🚀 FHIR (HAPI FHIR)
- hapi-fhir-base — core library
- hapi-fhir-structures-r4 — model R4
- hapi-fhir-client — REST client
- hapi-fhir-jpaserver-base — full FHIR server
- Alternatif: Microsoft FHIR SDK for Java
Kesimpulan
HL7 v2 dan FHIR bukan kompetitor — mereka adalah dua generasi standar yang melayani kebutuhan berbeda dan harus hidup berdampingan di dunia nyata. Hampir semua proyek healthcare integration yang serius saat ini membutuhkan kemampuan menangani keduanya.
Bagi Anda yang datang dari banking atau enterprise Java, fondasi yang sudah Anda miliki — pemahaman tentang messaging protocol, event-driven architecture, dan API security — adalah aset yang sangat berharga. Konteksnya berbeda (data klinis jauh lebih sensitif dan kompleks dari data finansial), namun pola teknisnya sangat paralel.
Saat ini saya sedang membangun project demo Spring Boot yang mengimplementasikan pipeline hybrid HL7 v2 → FHIR lengkap dengan unit test, integration test ke SATUSEHAT sandbox, dan deployment via Docker Compose. Jika Anda tertarik, saya akan share artikel lanjutan beserta link repository GitHub-nya.
💬 Ada Pertanyaan atau Pengalaman Serupa?
Punya pengalaman kerja dengan HL7 atau FHIR? Sedang mengerjakan proyek integrasi SATUSEHAT? Atau baru mulai belajar healthcare tech? Tinggalkan komentar di bawah — saya baca semua komentar dan senang berdiskusi.
Jika artikel ini bermanfaat, bagikan ke rekan engineer lainnya. Semakin banyak developer Indonesia yang menguasai standar ini, semakin baik infrastruktur kesehatan digital kita.
Comments
Post a Comment