Inti Sari
HL7 FHIR (Fast Healthcare Interoperability Resources) adalah standar modern untuk pertukaran data layanan kesehatan, menggunakan API RESTful dengan respons JSON/XML. Ini menyediakan sumber daya terstandardisasi untuk pasien, observasi, obat-obatan, dan lainnya, dengan autentikasi OAuth 2.0 dan SMART on FHIR untuk integrasi aplikasi. Panduan ini mencakup arsitektur FHIR, tipe sumber daya, parameter pencarian, autentikasi, dan strategi implementasi produksi.
Pendahuluan
Fragmentasi data layanan kesehatan merugikan sistem layanan kesehatan AS sebesar $30 miliar setiap tahun. Bagi pengembang yang membangun aplikasi layanan kesehatan, integrasi API HL7 FHIR bukanlah pilihan—ini adalah standar industri yang diwajibkan oleh CMS dan diadopsi oleh Epic, Cerner, serta semua vendor EHR utama.
Inilah kenyataannya: penyedia layanan yang menggunakan aplikasi berkemampuan FHIR mengurangi waktu koordinasi perawatan sebesar 40% dan menghilangkan 85% permintaan catatan berbasis faks. Integrasi API FHIR yang solid memungkinkan pertukaran data yang lancar di seluruh EHR, portal pasien, dan platform koordinasi perawatan.
Panduan ini membahas proses integrasi API HL7 FHIR secara lengkap. Anda akan mempelajari arsitektur FHIR, tipe sumber daya, parameter pencarian, autentikasi OAuth 2.0, integrasi SMART on FHIR, dan strategi penerapan produksi. Pada akhirnya, Anda akan memiliki integrasi FHIR yang siap produksi.
💡 Tips:
Apidog menyederhanakan integrasi API layanan kesehatan. Uji endpoint FHIR, validasi skema sumber daya, debug alur autentikasi, dan dokumentasikan spesifikasi API dalam satu workspace. Impor Panduan Implementasi FHIR, respons tiruan, dan bagikan skenario pengujian dengan tim Anda.
Apa Itu HL7 FHIR?
FHIR (Fast Healthcare Interoperability Resources) adalah kerangka kerja standar untuk pertukaran informasi layanan kesehatan secara elektronik. Dikembangkan oleh Health Level Seven International (HL7), FHIR menggunakan teknologi web modern termasuk API RESTful, JSON, XML, dan OAuth 2.0.
Tipe Sumber Daya FHIR
FHIR mendefinisikan lebih dari 140 tipe sumber daya. Berikut sumber daya inti dan kasus penggunaannya:
| Sumber Daya | Tujuan | Kasus Penggunaan Umum |
|---|---|---|
| Pasien | Demografi | Pencarian pasien, pendaftaran |
| Praktisi | Info penyedia | Direktori, penjadwalan |
| Perjumpaan | Kunjungan/penerimaan | Episode perawatan, penagihan |
| Observasi | Data klinis | Tanda vital, hasil lab, penilaian |
| Kondisi | Masalah/diagnosis | Daftar masalah, perencanaan perawatan |
| Permintaan Obat | Resep | Resep elektronik, riwayat obat |
| AlergiIntoleransi | Alergi | Pemeriksaan keamanan, peringatan |
| Imunisasi | Vaksinasi | Catatan imunisasi |
| Laporan Diagnostik | Laporan lab/pencitraan | Pengiriman hasil |
| Referensi Dokumen | Dokumen klinis | CCD, ringkasan keluar |
Arsitektur API FHIR
FHIR menggunakan pola endpoint RESTful:
https://fhir-server.com/fhir/{resourceType}/{id}
Perbandingan Versi FHIR
| Versi | Status | Kasus Penggunaan |
|---|---|---|
| R4 (4.0.1) | STU Saat Ini | Implementasi produksi |
| R4B (4.3) | Implementasi Uji Coba | Pengguna awal |
| R5 (5.0.0) | Draf STU | Implementasi masa depan |
| DSTU2 | Ditinggalkan | Hanya sistem lama |
CMS mewajibkan EHR Bersertifikat untuk mendukung FHIR R4.
Memulai: Akses Server FHIR
Langkah 1: Pilih Server FHIR Anda
Pilih platform sesuai kebutuhan:
| Server | Tipe | Biaya | Terbaik Untuk |
|---|---|---|---|
| Azure API for FHIR | Terkelola | Bayar-per-penggunaan | Perusahaan, pengguna Azure |
| AWS HealthLake | Terkelola | Bayar-per-penggunaan | Lingkungan AWS |
| Google Cloud Healthcare API | Terkelola | Bayar-per-penggunaan | Lingkungan GCP |
| HAPI FHIR | Sumber Terbuka | Dihosting sendiri | Penerapan kustom |
| Epic FHIR Server | Komersial | Pelanggan Epic | Integrasi EHR Epic |
| Cerner Ignite FHIR | Komersial | Pelanggan Cerner | Integrasi EHR Cerner |
Langkah 2: Dapatkan Kredensial Server
Contoh setup server cloud:
# Azure API for FHIR
# 1. Buat Layanan FHIR di Azure Portal
# 2. Konfigurasi autentikasi (OAuth 2.0 atau AAD)
# 3. Dapatkan endpoint FHIR: https://{nama-layanan}.azurehealthcareapis.com
# 4. Daftarkan aplikasi klien untuk OAuth
# AWS HealthLake
# 1. Buat Data Store di AWS Console
# 2. Konfigurasi peran IAM
# 3. Dapatkan endpoint: https://healthlake.{wilayah}.amazonaws.com
Langkah 3: Pahami Operasi RESTful FHIR
FHIR menggunakan metode HTTP standar:
| Operasi | Metode HTTP | Endpoint | Deskripsi |
|---|---|---|---|
| Baca | GET | /{resourceType}/{id} |
Dapatkan sumber daya spesifik |
| Cari | GET | /{resourceType}?param=value |
Cari sumber daya |
| Buat | POST | /{resourceType} |
Buat sumber daya baru |
| Perbarui | PUT | /{resourceType}/{id} |
Ganti sumber daya |
| Tambal | PATCH | /{resourceType}/{id} |
Pembaruan sebagian |
| Hapus | DELETE | /{resourceType}/{id} |
Hapus sumber daya |
| Riwayat | GET | /{resourceType}/{id}/_history |
Versi sumber daya |
Langkah 4: Lakukan Panggilan FHIR Pertama Anda
Uji koneksi ke server:
curl -X GET "https://fhir-server.com/fhir/metadata" \
-H "Accept: application/fhir+json" \
-H "Authorization: Bearer {token}"
Respons:
{
"resourceType": "CapabilityStatement",
"status": "active",
"date": "2026-03-25",
"fhirVersion": "4.0.1",
"rest": [{
"mode": "server",
"resource": [
{ "type": "Patient" },
{ "type": "Observation" },
{ "type": "Condition" }
]
}]
}
Operasi Inti FHIR
Membaca Sumber Daya Pasien
Ambil data pasien by ID:
const FHIR_BASE_URL = process.env.FHIR_BASE_URL;
const FHIR_TOKEN = process.env.FHIR_TOKEN;
const fhirRequest = async (endpoint, options = {}) => {
const response = await fetch(`${FHIR_BASE_URL}/fhir${endpoint}`, {
...options,
headers: {
'Accept': 'application/fhir+json',
'Authorization': `Bearer ${FHIR_TOKEN}`,
...options.headers
}
});
if (!response.ok) {
const error = await response.json();
throw new Error(`FHIR Error: ${error.issue?.[0]?.details?.text || response.statusText}`);
}
return response.json();
};
// Baca pasien
const getPatient = async (patientId) => {
const patient = await fhirRequest(`/Patient/${patientId}`);
return patient;
};
// Penggunaan
const patient = await getPatient('12345');
console.log(`Pasien: ${patient.name[0].given[0]} ${patient.name[0].family}`);
console.log(`Tanggal Lahir: ${patient.birthDate}`);
console.log(`Jenis Kelamin: ${patient.gender}`);
Struktur Sumber Daya Pasien
{
"resourceType": "Patient",
"id": "12345",
"identifier": [
{
"use": "usual",
"type": {
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/v2-0203",
"code": "MR"
}]
},
"system": "http://hospital.example.org",
"value": "MRN123456"
}
],
"name": [
{
"use": "official",
"family": "Smith",
"given": ["John", "Michael"]
}
],
"telecom": [
{
"system": "phone",
"value": "555-123-4567",
"use": "home"
},
{
"system": "email",
"value": "john.smith@email.com"
}
],
"gender": "male",
"birthDate": "1985-06-15",
"address": [
{
"use": "home",
"line": ["123 Main Street"],
"city": "Springfield",
"state": "IL",
"postalCode": "62701"
}
]
}
Mencari Sumber Daya
Cari pasien berdasarkan parameter:
const searchPatients = async (searchParams) => {
const query = new URLSearchParams();
if (searchParams.name) query.append('name', searchParams.name);
if (searchParams.birthDate) query.append('birthdate', searchParams.birthDate);
if (searchParams.identifier) query.append('identifier', searchParams.identifier);
if (searchParams.gender) query.append('gender', searchParams.gender);
const response = await fhirRequest(`/Patient?${query.toString()}`);
return response;
};
// Penggunaan
const results = await searchPatients({ name: 'Smith', birthDate: '1985-06-15' });
console.log(`Ditemukan ${results.total} pasien`);
results.entry.forEach(entry => {
const patient = entry.resource;
console.log(`${patient.name[0].family}, ${patient.name[0].given[0]}`);
});
Parameter Pencarian Umum
| Sumber Daya | Parameter Pencarian | Contoh |
|---|---|---|
| Pasien | nama, tanggal lahir, pengidentifikasi, jenis kelamin, telepon, email | ?name=Smith&birthdate=1985-06-15 |
| Observasi | pasien, kode, tanggal, kategori, status | ?patient=123&code=8480-6&date=ge2026-01-01 |
| Kondisi | pasien, status-klinis, kategori, tanggal-mulai | ?patient=123&clinical-status=active |
| Permintaan Obat | pasien, status, tujuan, obat | ?patient=123&status=active |
| Perjumpaan | pasien, tanggal, status, kelas | ?patient=123&date=ge2026-01-01 |
| Laporan Diagnostik | pasien, kategori, tanggal, status | ?patient=123&category=laboratory |
Pengubah & Awalan Pencarian
Pengubah Pencarian
| Pengubah | Deskripsi | Contoh |
|---|---|---|
:exact |
Kecocokan persis | name:exact=Smith |
:contains |
Mengandung | name:contains=smi |
:missing |
Nilai hilang/ada | phone:missing=true |
: (awalan) |
Operator awalan | birthdate=ge1980-01-01 |
Awalan Tanggal/Angka
| Awalan | Arti | Contoh |
|---|---|---|
eq |
Sama dengan | birthdate=eq1985-06-15 |
ne |
Tidak sama dengan | birthdate=ne1985-06-15 |
gt |
Lebih besar dari | birthdate=gt1980-01-01 |
lt |
Lebih kecil dari | birthdate=lt1990-01-01 |
ge |
Lebih besar atau sama dengan | birthdate=ge1980-01-01 |
le |
Lebih kecil atau sama dengan | birthdate=le1990-01-01 |
sa |
Dimulai setelah | date=sa2026-01-01 |
eb |
Berakhir sebelum | date=eb2026-12-31 |
Bekerja dengan Data Klinis
Membuat Observasi (Tanda Vital)
Rekam tanda vital pasien:
const createObservation = async (observationData) => {
const observation = {
resourceType: 'Observation',
status: 'final',
category: [
{
coding: [{
system: 'http://terminology.hl7.org/CodeSystem/observation-category',
code: 'vital-signs'
}]
}
],
code: {
coding: [{
system: 'http://loinc.org',
code: observationData.code,
display: observationData.display
}]
},
subject: {
reference: `Patient/${observationData.patientId}`
},
effectiveDateTime: observationData.effectiveDate || new Date().toISOString(),
valueQuantity: {
value: observationData.value,
unit: observationData.unit,
system: 'http://unitsofmeasure.org',
code: observationData.ucumCode
},
performer: [
{
reference: `Practitioner/${observationData.performerId}`
}
]
};
const response = await fhirRequest('/Observation', {
method: 'POST',
body: JSON.stringify(observation)
});
return response;
};
// Catat tekanan darah sistolik
const systolicBP = await createObservation({
patientId: '12345',
code: '8480-6',
display: 'Tekanan darah sistolik',
value: 120,
unit: 'mmHg',
ucumCode: 'mm[Hg]',
performerId: '67890'
});
console.log(`Observasi dibuat: ${systolicBP.id}`);
Kode LOINC Umum
| Kode | Tampilan | Kategori |
|---|---|---|
| 8480-6 | Tekanan darah sistolik | Tanda vital |
| 8462-4 | Tekanan darah diastolik | Tanda vital |
| 8867-4 | Denyut jantung | Tanda vital |
| 8310-5 | Suhu tubuh | Tanda vital |
| 8302-2 | Tinggi badan | Tanda vital |
| 29463-7 | Berat badan | Tanda vital |
| 8871-5 | Laju pernapasan | Tanda vital |
| 2339-0 | Glukosa [Massa/volume] | Laboratorium |
| 4548-4 | Hemoglobin A1c | Laboratorium |
| 2093-3 | Kolesterol [Massa/volume] | Laboratorium |
Membuat Kondisi (Problem List Entry)
Tambahkan diagnosis ke daftar masalah:
const createCondition = async (conditionData) => {
const condition = {
resourceType: 'Condition',
clinicalStatus: {
coding: [{
system: 'http://terminology.hl7.org/CodeSystem/condition-clinical',
code: conditionData.status || 'active'
}]
},
verificationStatus: {
coding: [{
system: 'http://terminology.hl7.org/CodeSystem/condition-ver-status',
code: 'confirmed'
}]
},
category: [
{
coding: [{
system: 'http://terminology.hl7.org/CodeSystem/condition-category',
code: conditionData.category || 'problem-list-item'
}]
}
],
code: {
coding: [{
system: 'http://snomed.info/sct',
code: conditionData.sctCode,
display: conditionData.display
}]
},
subject: {
reference: `Patient/${conditionData.patientId}`
},
onsetDateTime: conditionData.onsetDate,
recordedDate: new Date().toISOString()
};
const response = await fhirRequest('/Condition', {
method: 'POST',
body: JSON.stringify(condition)
});
return response;
};
// Tambahkan diabetes ke daftar masalah
const diabetes = await createCondition({
patientId: '12345',
sctCode: '44054006',
display: 'Diabetes Mellitus Tipe 2',
status: 'active',
category: 'problem-list-item',
onsetDate: '2024-01-15'
});
Kode SNOMED CT Umum
| Kode | Tampilan | Kategori |
|---|---|---|
| 44054006 | Diabetes Mellitus Tipe 2 | Masalah |
| 38341003 | Hipertensi | Masalah |
| 195967001 | Asma | Masalah |
| 13645005 | Penyakit Paru Obstruktif Kronis | Masalah |
| 35489007 | Gangguan Depresif | Masalah |
| 22298006 | Infark Miokard | Masalah |
| 26929004 | Penyakit Alzheimer | Masalah |
| 396275006 | Osteoartritis | Masalah |
Mengambil Obat Pasien
Ambil permintaan obat aktif:
const getPatientMedications = async (patientId) => {
const response = await fhirRequest(
`/MedicationRequest?patient=${patientId}&status=active`
);
return response;
};
// Penggunaan
const medications = await getPatientMedications('12345');
medications.entry?.forEach(entry => {
const med = entry.resource;
console.log(`${med.medicationCodeableConcept.coding[0].display}`);
console.log(` Dosis: ${med.dosageInstruction[0]?.text}`);
console.log(` Status: ${med.status}`);
});
Mengambil Hasil Lab
Ambil laporan diagnostik atau observasi spesifik:
const getPatientLabResults = async (patientId, options = {}) => {
const params = new URLSearchParams({
patient: patientId,
category: options.category || 'laboratory'
});
if (options.dateFrom) {
params.append('date', `ge${options.dateFrom}`);
}
const response = await fhirRequest(`/DiagnosticReport?${params.toString()}`);
return response;
};
// Dapatkan tes lab spesifik (misal HbA1c)
const getLabValue = async (patientId, loincCode) => {
const params = new URLSearchParams({
patient: patientId,
code: loincCode
});
const response = await fhirRequest(`/Observation?${params.toString()}`);
return response;
};
// Penggunaan - HbA1c
const hba1c = await getLabValue('12345', '4548-4');
hba1c.entry?.forEach(entry => {
const obs = entry.resource;
console.log(`HbA1c: ${obs.valueQuantity.value} ${obs.valueQuantity.unit}`);
console.log(`Tanggal: ${obs.effectiveDateTime}`);
});
OAuth 2.0 dan SMART on FHIR
Memahami Autentikasi FHIR
Server FHIR umumnya menerapkan OAuth 2.0 (OpenID Connect):
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Klien │───▶│ Server │───▶│ Server │
│ (Aplikasi)│ │ Autentikasi │ │ FHIR │
└─────────────┘ └─────────────┘ └─────────────┘
Alur:
- Klien meminta autentikasi ke server auth
- User login
- Server mengembalikan auth code
- Klien tukar code ke token
- Token digunakan untuk akses API FHIR
Peluncuran Aplikasi SMART on FHIR
Implementasi PKCE dan OAuth 2.0:
const crypto = require('crypto');
class SMARTClient {
constructor(config) {
this.clientId = config.clientId;
this.redirectUri = config.redirectUri;
this.issuer = config.issuer; // URL server FHIR
this.scopes = config.scopes;
}
generatePKCE() {
const codeVerifier = crypto.randomBytes(32).toString('base64url');
const codeChallenge = crypto
.createHash('sha256')
.update(codeVerifier)
.digest('base64url');
return { codeVerifier, codeChallenge };
}
buildAuthUrl(state, patientId = null) {
const { codeVerifier, codeChallenge } = this.generatePKCE();
this.codeVerifier = codeVerifier;
const params = new URLSearchParams({
response_type: 'code',
client_id: this.clientId,
redirect_uri: this.redirectUri,
scope: this.scopes.join(' '),
state: state,
code_challenge: codeChallenge,
code_challenge_method: 'S256',
aud: this.issuer,
launch: patientId ? `patient-${patientId}` : null
});
return `${this.issuer}/authorize?${params.toString()}`;
}
async exchangeCodeForToken(code) {
const response = await fetch(`${this.issuer}/token`, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code: code,
redirect_uri: this.redirectUri,
client_id: this.clientId,
code_verifier: this.codeVerifier
})
});
const data = await response.json();
return {
accessToken: data.access_token,
refreshToken: data.refresh_token,
expiresIn: data.expires_in,
patientId: data.patient,
encounterId: data.encounter
};
}
}
// Penggunaan
const smartClient = new SMARTClient({
clientId: 'my-app-client-id',
redirectUri: 'https://myapp.com/callback',
issuer: 'https://fhir.epic.com',
scopes: [
'openid',
'profile',
'patient/Patient.read',
'patient/Observation.read',
'patient/Condition.read',
'patient/MedicationRequest.read',
'offline_access'
]
});
const state = crypto.randomBytes(16).toString('hex');
const authUrl = smartClient.buildAuthUrl(state);
console.log(`Arahkan ke: ${authUrl}`);
Lingkup SMART yang Diperlukan
| Lingkup | Izin | Kasus Penggunaan |
|---|---|---|
openid |
Autentikasi OIDC | Diperlukan untuk semua aplikasi |
profile |
Info profil pengguna | Direktori penyedia |
patient/Patient.read |
Baca demografi pasien | Pencarian pasien |
patient/Observation.read |
Baca observasi | Tanda vital, lab |
patient/Condition.read |
Baca kondisi | Daftar masalah |
patient/MedicationRequest.read |
Baca obat-obatan | Riwayat obat |
patient/*.read |
Baca semua sumber daya pasien | Data pasien lengkap |
user/*.read |
Baca semua sumber daya yang dapat diakses | Tampilan penyedia |
offline_access |
Token penyegaran | Sesi jangka panjang |
Membuat Permintaan FHIR yang Diautentikasi
class FHIRClient {
constructor(accessToken, fhirBaseUrl) {
this.accessToken = accessToken;
this.baseUrl = fhirBaseUrl;
}
async request(endpoint, options = {}) {
const response = await fetch(`${this.baseUrl}/fhir${endpoint}`, {
...options,
headers: {
'Accept': 'application/fhir+json',
'Authorization': `Bearer ${this.accessToken}`,
...options.headers
}
});
if (!response.ok) {
const error = await response.json();
throw new Error(`FHIR Error: ${error.issue?.[0]?.details?.text}`);
}
return response.json();
}
async getPatient(patientId) {
return this.request(`/Patient/${patientId}`);
}
async searchPatients(params) {
const query = new URLSearchParams(params);
return this.request(`/Patient?${query.toString()}`);
}
}
// Penggunaan setelah callback OAuth
const fhirClient = new FHIRClient(tokens.accessToken, 'https://fhir.epic.com');
const patient = await fhirClient.getPatient(tokens.patientId);
Operasi Batch dan Transaksi
Permintaan Batch
Jalankan banyak permintaan sekaligus:
const batchRequest = async (requests) => {
const bundle = {
resourceType: 'Bundle',
type: 'batch',
entry: requests.map(req => ({
resource: req.resource,
request: {
method: req.method,
url: req.url
}
}))
};
const response = await fhirRequest('', {
method: 'POST',
body: JSON.stringify(bundle)
});
return response;
};
// Contoh: Ambil beberapa sumber daya sekaligus
const bundle = await batchRequest([
{ method: 'GET', url: 'Patient/12345' },
{ method: 'GET', url: 'Patient/12345/Observation?category=vital-signs' },
{ method: 'GET', url: 'Patient/12345/Condition?clinical-status=active' }
]);
bundle.entry.forEach((entry, index) => {
console.log(`Respons ${index}: ${entry.response.status}`);
console.log(entry.resource);
});
Permintaan Transaksi
Jalankan beberapa permintaan sebagai satu unit atomik:
const transactionRequest = async (requests) => {
const bundle = {
resourceType: 'Bundle',
type: 'transaction',
entry: requests.map(req => ({
resource: req.resource,
request: {
method: req.method,
url: req.url
}
}))
};
const response = await fhirRequest('', {
method: 'POST',
body: JSON.stringify(bundle)
});
return response;
};
// Contoh: Buat pasien dan kondisi sekaligus
const transaction = await transactionRequest([
{
method: 'POST',
url: 'Patient',
resource: {
resourceType: 'Patient',
name: [{ family: 'Doe', given: ['Jane'] }],
gender: 'female',
birthDate: '1990-01-01'
}
},
{
method: 'POST',
url: 'Condition',
resource: {
resourceType: 'Condition',
clinicalStatus: { coding: [{ code: 'active' }] },
code: { coding: [{ system: 'http://snomed.info/sct', code: '38341003' }] },
subject: { reference: 'Patient/-1' }
}
}
]);
Langganan dan Webhook
Langganan FHIR (R4B+)
Berlangganan perubahan pada sumber daya:
const createSubscription = async (subscriptionData) => {
const subscription = {
resourceType: 'Subscription',
status: 'requested',
criteria: subscriptionData.criteria,
reason: subscriptionData.reason,
channel: {
type: 'rest-hook',
endpoint: subscriptionData.endpoint,
payload: 'application/fhir+json'
}
};
const response = await fhirRequest('/Subscription', {
method: 'POST',
body: JSON.stringify(subscription)
});
return response;
};
// Contoh: Berlangganan hasil lab baru
const subscription = await createSubscription({
criteria: 'DiagnosticReport?category=laboratory&patient=12345',
reason: 'Pantau hasil lab pasien',
endpoint: 'https://myapp.com/webhooks/fhir'
});
Menangani Webhook FHIR
const express = require('express');
const app = express();
app.post('/webhooks/fhir', express.json({ type: 'application/fhir+json' }), async (req, res) => {
const notification = req.body;
// Verifikasi referensi langganan
if (notification.subscription !== expectedSubscription) {
return res.status(401).send('Tidak Sah');
}
// Proses notifikasi
if (notification.event?.resourceType === 'DiagnosticReport') {
const reportId = notification.event.resourceId;
const report = await fhirRequest(`/DiagnosticReport/${reportId}`);
// Proses hasil lab baru
await processLabResult(report);
}
res.status(200).send('OK');
});
Memecahkan Masalah Umum
Masalah: 401 Tidak Sah
Solusi:
- Pastikan token masih aktif
- Periksa lingkup token mencakup resource yang diakses
- Header
Authorization: Bearer {token}wajib ada - Endpoint FHIR sesuai audience token
Masalah: 403 Dilarang
Solusi:
- Cek izin user pada resource
- Konteks pasien sesuai token
- Lingkup SMART sesuai operasi
- Kontrol akses resource
Masalah: 404 Tidak Ditemukan
Solusi:
- ID resource benar
- URL dasar FHIR sesuai
- Resource type didukung server
- Endpoint versi FHIR cocok (R4, R4B)
Masalah: 422 Entitas Tidak Dapat Diproses
Solusi:
// Debug error validasi
const error = await response.json();
error.issue?.forEach(issue => {
console.log(`Tingkat Keparahan: ${issue.severity}`);
console.log(`Lokasi: ${issue.expression?.join('.')}`);
console.log(`Pesan: ${issue.details?.text}`);
});
Cek field wajib, validitas kode, referensi, dan format tanggal.
Daftar Periksa Penerapan Produksi
Checklist sebelum go-live:
- [ ] Konfigurasi OAuth 2.0 + SMART on FHIR
- [ ] Implementasi refresh token
- [ ] Penanganan error komprehensif
- [ ] Logging (tanpa PHI)
- [ ] Rate limiting
- [ ] Retry + backoff eksponensial
- [ ] Uji lintas vendor EHR
- [ ] Validasi dengan FHIR validator
- [ ] Dokumentasi endpoint FHIR
- [ ] Monitoring & alerting
- [ ] Runbook troubleshooting
Validasi FHIR
const { FhirValidator } = require('fhir-validator');
const validator = new FhirValidator('4.0.1');
const validateResource = async (resource) => {
const validationResult = await validator.validate(resource);
if (!validationResult.valid) {
validationResult.issues.forEach(issue => {
console.error(`Kesalahan Validasi: ${issue.message}`);
console.error(`Lokasi: ${issue.path}`);
});
throw new Error('Validasi sumber daya gagal');
}
return true;
};
// Validasi sebelum create/update
await validateResource(patientResource);
Kasus Penggunaan Dunia Nyata
Integrasi Portal Pasien
- Tantangan: Pasien tidak bisa akses catatan antar penyedia
- Solusi: Aplikasi SMART on FHIR terintegrasi Epic & Cerner
- Hasil: 80% adopsi pasien, 50% pengurangan permintaan catatan
Implementasi:
- SMART launch untuk pasien
- Read-only akses Pasien, Observasi, Kondisi, MedicationRequest
- Refresh token untuk sesi panjang
- UI mobile friendly
Dukungan Keputusan Klinis
- Tantangan: Kesenjangan perawatan tidak terdeteksi
- Solusi: Kueri FHIR real-time untuk gap perawatan
- Hasil: Skor HEDIS naik 25%
Implementasi:
- SMART provider app
- Query Pasien, Kondisi, Observasi, Imunisasi
- Algoritma gap care terotomatisasi
- Rekomendasi terintegrasi EHR
Analitik Kesehatan Populasi
- Tantangan: Data tidak lengkap antar jaringan
- Solusi: Ekspor data massal FHIR ($export)
- Hasil: Tampilan 360° pasien, biaya PMPM turun
Implementasi:
- Bulk Data FHIR
- Ekspor batch ke data warehouse
- Stratifikasi risiko otomatis
- Alert untuk care manager
Kesimpulan
HL7 FHIR adalah fondasi interoperabilitas layanan kesehatan modern.
- FHIR R4 = standar API kesehatan saat ini
- SMART on FHIR = OAuth 2.0 aman untuk aplikasi
- Resource type menstandardisasi data klinis
- Parameter pencarian = query fleksibel
- Batch & transaksi = workflow kompleks
- Apidog membantu pengujian & dokumentasi FHIR API
Bagian FAQ
Untuk apa HL7 FHIR digunakan?
FHIR memfasilitasi pertukaran data terstandardisasi antar EHR, portal pasien, aplikasi mobile, dan sistem IT kesehatan lainnya. Contoh: akses pasien, CDS, analitik populasi, koordinasi perawatan.
Bagaimana cara memulai dengan FHIR?
Gunakan server FHIR publik (misal HAPI FHIR) atau setup FHIR cloud (Azure, AWS). Praktikkan operasi GET/POST, pahami resource & parameter pencarian.
Apa perbedaan HL7 v2 dan FHIR?
HL7 v2 = pesan event-driven (ADT/ORM/ORU) berbasis teks.
FHIR = API RESTful JSON/XML resource-based, lebih mudah untuk web/mobile modern.
Apakah FHIR patuh HIPAA?
FHIR adalah standar data. Kepatuhan HIPAA tergantung implementasi: enkripsi, auth, akses, audit. Gunakan OAuth 2.0 + SMART on FHIR untuk keamanan.
Apa itu lingkup SMART?
Lingkup SMART = izin granular akses FHIR (misal, patient/Observation.read). Aplikasi hanya minta scope yang dibutuhkan.
Bagaimana cara mencari sumber daya di FHIR?
Gunakan GET dengan query parameter: /Patient?name=Smith&birthdate=ge1980-01-01. FHIR dukung search modifier (:exact, :contains) & prefix (gt, lt, ge, le).
Apa itu Bulk FHIR?
Bulk FHIR ($export) = ekspor NDJSON asinkron dataset besar. Cocok untuk analitik, warehouse, kesehatan populasi.
Bagaimana cara menangani pembuatan versi FHIR?
Gunakan versi spesifik endpoint (disarankan R4). Cek CapabilityStatement server untuk resource & versi yang didukung.
Bisakah FHIR diperluas dengan field custom?
Ya, gunakan ekstensi FHIR untuk elemen data kustom. Definisikan di Implementation Guide, daftarkan ke HL7 bila perlu.
Alat bantu pengembangan FHIR?
HAPI FHIR (server open source), validator FHIR, Postman collection, dan Apidog untuk testing & dokumentasi API.

Top comments (0)