DEV Community

Cover image for Cara Menggunakan HL7 FHIR API: Panduan Integrasi Sistem Kesehatan Lengkap (2026)
Walse
Walse

Posted on • Originally published at apidog.com

Cara Menggunakan HL7 FHIR API: Panduan Integrasi Sistem Kesehatan Lengkap (2026)

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.

Coba Apidog hari ini

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.

Bagaimana HL7 FHIR bekerja

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}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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}"
Enter fullscreen mode Exit fullscreen mode

Respons:

{
  "resourceType": "CapabilityStatement",
  "status": "active",
  "date": "2026-03-25",
  "fhirVersion": "4.0.1",
  "rest": [{
    "mode": "server",
    "resource": [
      { "type": "Patient" },
      { "type": "Observation" },
      { "type": "Condition" }
    ]
  }]
}
Enter fullscreen mode Exit fullscreen mode

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}`);
Enter fullscreen mode Exit fullscreen mode

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"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

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]}`);
});
Enter fullscreen mode Exit fullscreen mode

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}`);
Enter fullscreen mode Exit fullscreen mode

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'
});
Enter fullscreen mode Exit fullscreen mode

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}`);
});
Enter fullscreen mode Exit fullscreen mode

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}`);
});
Enter fullscreen mode Exit fullscreen mode

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     │
└─────────────┘    └─────────────┘    └─────────────┘
Enter fullscreen mode Exit fullscreen mode

Alur:

  1. Klien meminta autentikasi ke server auth
  2. User login
  3. Server mengembalikan auth code
  4. Klien tukar code ke token
  5. 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}`);
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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);
});
Enter fullscreen mode Exit fullscreen mode

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' }
    }
  }
]);
Enter fullscreen mode Exit fullscreen mode

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'
});
Enter fullscreen mode Exit fullscreen mode

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');
});
Enter fullscreen mode Exit fullscreen mode

Memecahkan Masalah Umum

Masalah: 401 Tidak Sah

Solusi:

  1. Pastikan token masih aktif
  2. Periksa lingkup token mencakup resource yang diakses
  3. Header Authorization: Bearer {token} wajib ada
  4. Endpoint FHIR sesuai audience token

Masalah: 403 Dilarang

Solusi:

  1. Cek izin user pada resource
  2. Konteks pasien sesuai token
  3. Lingkup SMART sesuai operasi
  4. Kontrol akses resource

Masalah: 404 Tidak Ditemukan

Solusi:

  1. ID resource benar
  2. URL dasar FHIR sesuai
  3. Resource type didukung server
  4. 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}`);
});
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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)