ÖZET
HL7 FHIR (Hızlı Sağlık Hizmetleri Birlikte Çalışabilirlik Kaynakları), JSON/XML yanıtları ile RESTful API'ler kullanarak sağlık verisi değişimi için modern bir standarttır. Uygulama entegrasyonu için OAuth 2.0 kimlik doğrulama ve SMART on FHIR ile hastalar, gözlemler, ilaçlar ve daha fazlası için standartlaştırılmış kaynaklar sağlar. Bu kılavuz, FHIR mimarisini, kaynak türlerini, arama parametrelerini, kimlik doğrulamayı ve üretim uygulama stratejilerini kapsar.
Giriş
Sağlık verilerinin parçalanması, ABD sağlık sistemine yılda 30 milyar dolara mal olmaktadır. Sağlık hizmetleri uygulamaları geliştiren geliştiriciler için HL7 FHIR API entegrasyonu isteğe bağlı değildir; CMS tarafından zorunlu kılınan ve Epic, Cerner ve tüm büyük EHR satıcıları tarafından benimsenen endüstri standardıdır.
İşte gerçek: FHIR özellikli uygulamaları kullanan sağlayıcılar, bakım koordinasyon süresini %40 azaltır ve faks tabanlı kayıt taleplerinin %85'ini ortadan kaldırır. Sağlam bir FHIR API entegrasyonu, EHR'ler, hasta portalları ve bakım koordinasyon platformları arasında sorunsuz veri alışverişini sağlar.
Bu kılavuz, eksiksiz HL7 FHIR API entegrasyon sürecini anlatmaktadır. FHIR mimarisini, kaynak türlerini, arama parametrelerini, OAuth 2.0 kimlik doğrulamasını, SMART on FHIR entegrasyonunu ve üretim dağıtım stratejilerini öğreneceksiniz. Sonunda, üretime hazır bir FHIR entegrasyonuna sahip olacaksınız.
HL7 FHIR Nedir?
FHIR (Hızlı Sağlık Hizmetleri Birlikte Çalışabilirlik Kaynakları), sağlık bilgilerinin elektronik olarak alışverişi için bir standartlar çerçevesidir. Health Level Seven International (HL7) tarafından geliştirilen FHIR, RESTful API'ler, JSON, XML ve OAuth 2.0 dahil olmak üzere modern web teknolojilerini kullanır.

FHIR Kaynak Türleri
FHIR, 140'tan fazla kaynak türü tanımlar. Temel kaynaklar şunları içerir:
| Kaynak | Amaç | Yaygın Kullanım Senaryoları |
|---|---|---|
| Hasta | Demografik Bilgiler | Hasta araması, kayıt |
| Uygulayıcı | Sağlayıcı Bilgisi | Dizin, randevu planlama |
| Görüşme | Ziyaretler/kabuller | Bakım epizotları, faturalama |
| Gözlem | Klinik veriler | Vital bulgular, laboratuvar sonuçları, değerlendirmeler |
| Durum | Sorunlar/teşhisler | Sorun listeleri, bakım planlama |
| İlaç Talebi | Reçeteler | e-Reçete, ilaç geçmişi |
| Alerjiİntoleransı | Alerjiler | Güvenlik kontrolleri, uyarılar |
| Aşılama | Aşılar | Aşılama kayıtları |
| Tanı Raporu | Laboratuvar/görüntüleme raporları | Sonuç teslimi |
| BelgeReferansı | Klinik belgeler | CCD, taburcu özetleri |
FHIR API Mimarisi
FHIR, RESTful bir API yapısı kullanır:
https://fhir-server.com/fhir/{resourceType}/{id}
FHIR Sürümleri Karşılaştırması
| Sürüm | Durum | Kullanım Senaryosu |
|---|---|---|
| R4 (4.0.1) | Mevcut STU | Üretim uygulamaları |
| R4B (4.3) | Deneme Uygulaması | Erken benimseyenler |
| R5 (5.0.0) | Taslak STU | Gelecek uygulamalar |
| DSTU2 | Kullanımdan Kaldırıldı | Yalnızca eski sistemler |
CMS, Sertifikalı EHR'lerin Hasta Erişimi ve Sağlayıcı Erişimi API'leri için FHIR R4'ü desteklemesini gerektirir.
Başlarken: FHIR Sunucu Erişimi
Adım 1: FHIR Sunucunuzu Seçin
FHIR sunucu dağıtımı için seçenekler:
| Sunucu | Tür | Maliyet | En İyisi İçin |
|---|---|---|---|
| FHIR için Azure API | Yönetilen | Kullanım başına ödeme | Kurumsal, Azure kullananlar |
| AWS HealthLake | Yönetilen | Kullanım başına ödeme | AWS ortamları |
| Google Cloud Healthcare API | Yönetilen | Kullanım başına ödeme | GCP ortamları |
| HAPI FHIR | Açık Kaynak | Kendi barındırılan | Özel dağıtımlar |
| Epic FHIR Sunucusu | Ticari | Epic müşterileri | Epic EHR entegrasyonu |
| Cerner Ignite FHIR | Ticari | Cerner müşterileri | Cerner EHR entegrasyonu |
Adım 2: Sunucu Kimlik Bilgilerini Alın
Bulut FHIR hizmetleri için:
# Azure API for FHIR
# 1. Create FHIR Service in Azure Portal
# 2. Configure authentication (OAuth 2.0 or AAD)
# 3. Get FHIR endpoint: https://{service-name}.azurehealthcareapis.com
# 4. Register client app for OAuth
# AWS HealthLake
# 1. Create Data Store in AWS Console
# 2. Configure IAM roles
# 3. Get endpoint: https://healthlake.{region}.amazonaws.com
Adım 3: FHIR RESTful İşlemlerini Anlayın
FHIR, standart HTTP yöntemlerini destekler:
| İşlem | HTTP Yöntemi | Uç Nokta | Açıklama |
|---|---|---|---|
| Oku | GET | /{resourceType}/{id} |
Belirli bir kaynağı al |
| Ara | GET | /{resourceType}?param=value |
Kaynakları ara |
| Oluştur | POST | /{resourceType} |
Yeni kaynak oluştur |
| Güncelle | PUT | /{resourceType}/{id} |
Kaynağı değiştir |
| Yama | PATCH | /{resourceType}/{id} |
Kısmi güncelleme |
| Sil | DELETE | /{resourceType}/{id} |
Kaynağı kaldır |
| Geçmiş | GET | /{resourceType}/{id}/_history |
Kaynak sürümleri |
Adım 4: İlk FHIR Çağrınızı Yapın
Bağlantıyı test edin:
curl -X GET "https://fhir-server.com/fhir/metadata" \
-H "Accept: application/fhir+json" \
-H "Authorization: Bearer {token}"
Beklenen yanıt:
{
"resourceType": "CapabilityStatement",
"status": "active",
"date": "2026-03-25",
"fhirVersion": "4.0.1",
"rest": [{
"mode": "server",
"resource": [
{ "type": "Patient" },
{ "type": "Observation" },
{ "type": "Condition" }
]
}]
}
Temel FHIR İşlemleri
Bir Hasta Kaynağını Okuma
ID'ye göre hastayı getir:
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();
};
// Read patient by ID
const getPatient = async (patientId) => {
const patient = await fhirRequest(`/Patient/${patientId}`);
return patient;
};
// Usage
const patient = await getPatient('12345');
console.log(`Patient: ${patient.name[0].given[0]} ${patient.name[0].family}`);
console.log(`DOB: ${patient.birthDate}`);
console.log(`Gender: ${patient.gender}`);
Hasta Kaynak Yapısı
{
"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"
}
]
}
Kaynakları Arama
Hastaları isme göre arayın:
const searchPatients = async (searchParams) => {
const query = new URLSearchParams();
// Add search parameters
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;
};
// Usage
const results = await searchPatients({ name: 'Smith', birthDate: '1985-06-15' });
console.log(`Found ${results.total} patients`);
results.entry.forEach(entry => {
const patient = entry.resource;
console.log(`${patient.name[0].family}, ${patient.name[0].given[0]}`);
});
Yaygın Arama Parametreleri
| Kaynak | Arama Parametreleri | Örnek |
|---|---|---|
| Hasta | isim, doğum tarihi, tanımlayıcı, cinsiyet, telefon, e-posta | ?name=Smith&birthdate=1985-06-15 |
| Gözlem | hasta, kod, tarih, kategori, durum | ?patient=123&code=8480-6&date=ge2026-01-01 |
| Durum | hasta, klinik durum, kategori, başlangıç tarihi | ?patient=123&clinical-status=active |
| İlaç Talebi | hasta, durum, amaç, ilaç | ?patient=123&status=active |
| Görüşme | hasta, tarih, durum, sınıf | ?patient=123&date=ge2026-01-01 |
| Tanı Raporu | hasta, kategori, tarih, durum | ?patient=123&category=laboratory |
Arama Değiştiricileri
| Değiştirici | Açıklama | Örnek |
|---|---|---|
:exact |
Tam eşleşme | name:exact=Smith |
:contains |
İçerir | name:contains=smi |
:missing |
Değeri var/eksik | phone:missing=true |
: (ön ek) |
Ön ek operatörleri | birthdate=ge1980-01-01 |
Tarihler ve Sayılar İçin Arama Ön Ekleri
| Ön Ek | Anlamı | Örnek |
|---|---|---|
eq |
Eşittir | birthdate=eq1985-06-15 |
ne |
Eşit değildir | birthdate=ne1985-06-15 |
gt |
Büyüktür | birthdate=gt1980-01-01 |
lt |
Küçüktür | birthdate=lt1990-01-01 |
ge |
Büyük veya eşittir | birthdate=ge1980-01-01 |
le |
Küçük veya eşittir | birthdate=le1990-01-01 |
sa |
Sonra başlar | date=sa2026-01-01 |
eb |
Önce biter | date=eb2026-12-31 |
Klinik Verilerle Çalışma
Bir Gözlem Oluşturma (Vital Bulgular)
Vital bulguları kaydedin:
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, // e.g., '8480-6' for Systolic BP
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;
};
// Usage - Record blood pressure
const systolicBP = await createObservation({
patientId: '12345',
code: '8480-6',
display: 'Systolic blood pressure',
value: 120,
unit: 'mmHg',
ucumCode: 'mm[Hg]',
performerId: '67890'
});
console.log(`Observation created: ${systolicBP.id}`);
Yaygın LOINC Kodları
| Kod | Görünen Adı | Kategori |
|---|---|---|
| 8480-6 | Sistolik kan basıncı | Vital bulgular |
| 8462-4 | Diyastolik kan basıncı | Vital bulgular |
| 8867-4 | Kalp hızı | Vital bulgular |
| 8310-5 | Vücut sıcaklığı | Vital bulgular |
| 8302-2 | Vücut boyu | Vital bulgular |
| 29463-7 | Vücut ağırlığı | Vital bulgular |
| 8871-5 | Solunum hızı | Vital bulgular |
| 2339-0 | Glikoz [Kütle/hacim] | Laboratuvar |
| 4548-4 | Hemoglobin A1c | Laboratuvar |
| 2093-3 | Kolesterol [Kütle/hacim] | Laboratuvar |
Bir Durum Oluşturma (Sorun Listesi Girişi)
Tanıyı sorun listesine ekleyin:
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;
};
// Usage - Add diabetes to problem list
const diabetes = await createCondition({
patientId: '12345',
sctCode: '44054006',
display: 'Type 2 Diabetes Mellitus',
status: 'active',
category: 'problem-list-item',
onsetDate: '2024-01-15'
});
Yaygın SNOMED CT Kodları
| Kod | Görünen Adı | Kategori |
|---|---|---|
| 44054006 | Tip 2 Diyabet Mellitus | Sorun |
| 38341003 | Hipertansiyon | Sorun |
| 195967001 | Astım | Sorun |
| 13645005 | Kronik Obstrüktif Akciğer Hastalığı | Sorun |
| 35489007 | Depresif Bozukluk | Sorun |
| 22298006 | Miyokard Enfarktüsü | Sorun |
| 26929004 | Alzheimer Hastalığı | Sorun |
| 396275006 | Osteoartrit | Sorun |
Hasta İlaçlarını Alma
Aktif ilaç taleplerini alın:
const getPatientMedications = async (patientId) => {
const response = await fhirRequest(
`/MedicationRequest?patient=${patientId}&status=active`
);
return response;
};
// Usage
const medications = await getPatientMedications('12345');
medications.entry?.forEach(entry => {
const med = entry.resource;
console.log(`${med.medicationCodeableConcept.coding[0].display}`);
console.log(` Dose: ${med.dosageInstruction[0]?.text}`);
console.log(` Status: ${med.status}`);
});
Laboratuvar Sonuçlarını Alma
Tanı raporlarını ve gözlemleri alın:
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;
};
// Get specific lab test (e.g., HbA1c)
const getLabValue = async (patientId, loincCode) => {
const params = new URLSearchParams({
patient: patientId,
code: loincCode
});
const response = await fhirRequest(`/Observation?${params.toString()}`);
return response;
};
// Usage - Get HbA1c results
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(`Date: ${obs.effectiveDateTime}`);
});
OAuth 2.0 ve SMART on FHIR
FHIR Kimlik Doğrulamasını Anlama
FHIR sunucuları, OpenID Connect ile OAuth 2.0 kullanır:
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ İstemci │───▶│ Kimlik │───▶│ FHIR │
│ (Uygulama)│ │ Doğrulama │ │ Sunucusu │
└─────────────┘ │ Sunucusu │ └─────────────┘
│ └─────────────┘ │
│ 1. Kimlik Doğrulama İsteği │
│─────────────────────────────────────▶│
│ │
│ 2. Kullanıcı Girişi │
│◀─────────────────────────────────────│
│ │
│ 3. Kimlik Doğrulama Kodu │
│─────────────────────────────────────▶│
│ │
│ 4. Token İsteği │
│─────────────────────────────────────▶│
│ │
│ 5. Token + ID │
│◀─────────────────────────────────────│
│ │
│ 6. API İsteği │
│───────────────────────────────────────────────────▶│
│ │
│ 7. FHIR Verileri │
│◀───────────────────────────────────────────────────│
SMART on FHIR Uygulama Başlatma
SMART uygulama başlatmayı uygulayın:
const crypto = require('crypto');
class SMARTClient {
constructor(config) {
this.clientId = config.clientId;
this.redirectUri = config.redirectUri;
this.issuer = config.issuer; // FHIR server URL
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();
// Store codeVerifier for token exchange
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
};
}
}
// Usage
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'
]
});
// Redirect user to auth URL
const state = crypto.randomBytes(16).toString('hex');
const authUrl = smartClient.buildAuthUrl(state);
console.log(`Redirect to: ${authUrl}`);
Gerekli SMART Kapsamları
| Kapsam | İzin | Kullanım Senaryosu |
|---|---|---|
openid |
OIDC kimlik doğrulaması | Tüm uygulamalar için gerekli |
profile |
Kullanıcı profili bilgisi | Sağlayıcı dizini |
patient/Patient.read |
Hasta demografik bilgilerini oku | Hasta araması |
patient/Observation.read |
Gözlemleri oku | Vital bulgular, laboratuvarlar |
patient/Condition.read |
Durumları oku | Sorun listeleri |
patient/MedicationRequest.read |
İlaçları oku | İlaç geçmişi |
patient/*.read |
Tüm hasta kaynaklarını oku | Tam hasta verileri |
user/*.read |
Erişilebilir tüm kaynakları oku | Sağlayıcı görünümü |
offline_access |
Yenileme token'ı | Uzun süreli oturumlar |
Kimliği Doğrulanmış FHIR İstekleri Yapma
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()}`);
}
}
// Usage after OAuth callback
const fhirClient = new FHIRClient(tokens.accessToken, 'https://fhir.epic.com');
const patient = await fhirClient.getPatient(tokens.patientId);
Toplu ve İşlem Operasyonları
Toplu İstekler
Birden fazla bağımsız isteği yürütün:
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;
};
// Usage - Fetch multiple resources
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(`Response ${index}: ${entry.response.status}`);
console.log(entry.resource);
});
İşlem İstekleri
Birden fazla isteği atomik birim olarak yürütün:
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;
};
// Usage - Create patient and related resources
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' } // Reference to first resource
}
}
]);
Abonelikler ve Web Kancaları
FHIR Abonelikleri (R4B+)
Kaynak değişikliklerine abone olun:
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;
};
// Usage - Subscribe to new lab results
const subscription = await createSubscription({
criteria: 'DiagnosticReport?category=laboratory&patient=12345',
reason: 'Monitor patient lab results',
endpoint: 'https://myapp.com/webhooks/fhir'
});
FHIR Web Kancalarını İşleme
const express = require('express');
const app = express();
app.post('/webhooks/fhir', express.json({ type: 'application/fhir+json' }), async (req, res) => {
const notification = req.body;
// Verify subscription reference
if (notification.subscription !== expectedSubscription) {
return res.status(401).send('Unauthorized');
}
// Process notification
if (notification.event?.resourceType === 'DiagnosticReport') {
const reportId = notification.event.resourceId;
const report = await fhirRequest(`/DiagnosticReport/${reportId}`);
// Process new lab result
await processLabResult(report);
}
res.status(200).send('OK');
});
Sık Karşılaşılan Sorunları Giderme
Sorun: 401 Yetkilendirilmemiş
Belirtiler: "Yetkilendirilmemiş" veya "Geçersiz token" hataları alınıyor.
Çözümler:
- Token'ın süresinin dolmadığını doğrulayın
- Token kapsamının talep edilen kaynağı içerdiğini kontrol edin
Authorization: Bearer {token}başlığının mevcut olduğundan emin olun- FHIR sunucu URL'sinin token hedefiyle eşleştiğini doğrulayın
Sorun: 403 Yasak
Belirtiler: Token geçerli ancak erişim reddedildi.
Çözümler:
- Kullanıcının talep edilen kaynak için izni olup olmadığını kontrol edin
- Hasta bağlamının eşleştiğini doğrulayın (hasta kapsamlı token'lar için)
- SMART kapsamlarının talep edilen işlemi içerdiğinden emin olun
- Kaynak düzeyindeki erişim kontrollerini kontrol edin
Sorun: 404 Bulunamadı
Belirtiler: Kaynak mevcut değil veya uç nokta yanlış.
Çözümler:
- Kaynak ID'sinin doğru olduğunu doğrulayın
- FHIR temel URL'sinin doğru olduğunu kontrol edin
- Kaynak türünün sunucu tarafından desteklendiğinden emin olun
- Sürüme özel uç noktayı doğrulayın (R4'e karşı R4B)
Sorun: 422 İşlenemeyen Varlık
Belirtiler: Oluşturma/güncelleme işlemlerinde doğrulama hataları.
Çözümler:
// Parse validation errors
const error = await response.json();
error.issue?.forEach(issue => {
console.log(`Severity: ${issue.severity}`);
console.log(`Location: ${issue.expression?.join('.')}`);
console.log(`Message: ${issue.details?.text}`);
});
Yaygın nedenler:
- Gerekli alanlar eksik
- Geçersiz kod sistemi değerleri
- Yanlış referans formatı
- Tarih formatı sorunları
Üretim Dağıtım Kontrol Listesi
Canlıya geçmeden önce:
- [ ] SMART on FHIR ile OAuth 2.0'ı yapılandırın
- [ ] Token yenileme mantığını uygulayın
- [ ] Uygun hata yönetimini kurun
- [ ] Kapsamlı günlük kaydı ekleyin (günlüklere PHI eklemeyin)
- [ ] Oran sınırlaması uygulayın
- [ ] Üstel geri çekilme ile yeniden deneme mantığını yapılandırın
- [ ] Birden fazla EHR satıcısıyla test edin
- [ ] FHIR doğrulayıcısına karşı doğrulayın
- [ ] Tüm FHIR işlemlerini belgeleyin
- [ ] İzleme ve uyarı sistemini kurun
- [ ] Yaygın sorunlar için bir runbook oluşturun
FHIR Doğrulaması
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(`Validation Error: ${issue.message}`);
console.error(`Location: ${issue.path}`);
});
throw new Error('Resource validation failed');
}
return true;
};
// Usage before create/update
await validateResource(patientResource);
Gerçek Dünya Kullanım Senaryoları
Hasta Portalı Entegrasyonu
Bir sağlık sistemi, hasta portalı oluşturur:
- Zorluk: Hastalar birden fazla sağlayıcıdan kayıtlara erişemiyordu
- Çözüm: Epic ve Cerner entegrasyonu ile SMART on FHIR uygulaması
- Sonuç: %80 hasta benimsemesi, kayıt taleplerinde %50 azalma
Temel uygulama:
- Hasta odaklı SMART uygulama başlatma
- Hasta, Gözlem, Durum, İlaç Talebi'ne salt okunur erişim
- Kalıcı oturumlar için token yenileme
- Mobil uyumlu kullanıcı arayüzü
Klinik Karar Desteği
Bir bakım yönetimi platformu CDS ekler:
- Zorluk: Sağlayıcılar önleyici bakım fırsatlarını kaçırıyordu
- Çözüm: Bakım eksiklikleri için gerçek zamanlı FHIR sorguları
- Sonuç: HEDIS skorlarında %25 iyileşme
Temel uygulama:
- Sağlayıcı odaklı SMART uygulaması
- Hasta, Durum, Gözlem, Aşılama sorgulama
- Kılavuzlara dayalı bakım eksikliklerini hesapla
- EHR iş akışında satır içi öneriler
Popülasyon Sağlığı Analizi
Bir ödeyici, popülasyon sağlığı paneli oluşturur:
- Zorluk: Sağlayıcı ağlarında eksik veriler
- Çözüm: Analiz için FHIR toplu veri dışa aktarımı
- Sonuç: 360 derecelik hasta görünümü, azaltılmış PMPM maliyetleri
Temel uygulama:
- FHIR Toplu Veri Erişimi ($export)
- Veri ambarına gece dışa aktarımları
- Risk katmanlama modelleri
- Bakım yöneticisi uyarıları
Sonuç
HL7 FHIR, modern sağlık hizmetleri birlikte çalışabilirliğinin temelini oluşturur. Temel çıkarımlar:
- FHIR R4, sağlık API entegrasyonu için mevcut standarttır
- SMART on FHIR, güvenli OAuth 2.0 kimlik doğrulamasını sağlar
- Kaynak türleri, hasta, gözlem, durum ve ilaç verilerini standartlaştırır
- Arama parametreleri esnek sorgulamayı sağlar
- Toplu ve işlem operasyonları karmaşık iş akışlarını destekler
- Apidog, FHIR API testini ve dokümantasyonunu kolaylaştırır
SSS Bölümü
HL7 FHIR ne için kullanılır?
FHIR, EHR'ler, hasta portalları, mobil uygulamalar ve diğer sağlık BT sistemleri arasında sağlık verilerinin standartlaştırılmış alışverişini sağlar. Yaygın kullanım senaryoları arasında hasta erişim uygulamaları, klinik karar desteği, popülasyon sağlığı ve bakım koordinasyonu bulunur.
FHIR'a nasıl başlarım?
Halka açık bir FHIR sunucusuna (HAPI FHIR test sunucusu gibi) erişerek veya bir bulut FHIR hizmeti (FHIR için Azure API, AWS HealthLake) kurarak başlayın. Kaynakları okuma ve arama parametrelerini kullanma pratiği yapın.
HL7 v2 ile FHIR arasındaki fark nedir?
HL7 v2, olay odaklı veri alışverişi için boruyla ayrılmış mesajlar (ADT, ORM, ORU) kullanır. FHIR, kaynak tabanlı erişim için JSON/XML ile RESTful API'ler kullanır. FHIR'ın uygulanması daha kolaydır ve modern web/mobil uygulamalar için daha uygundur.
FHIR HIPAA uyumlu mu?
FHIR'ın kendisi bir veri formatı standardıdır. HIPAA uyumluluğu, uygulamaya bağlıdır: şifreleme, kimlik doğrulama, erişim kontrolleri ve denetim kaydı. Güvenli erişim için SMART on FHIR ile OAuth 2.0 kullanın.
SMART kapsamları nelerdir?
SMART kapsamları, FHIR kaynakları için ayrıntılı erişim izinlerini tanımlar (örn. patient/Observation.read, user/*.read). Uygulamanızın yalnızca ihtiyaç duyduğu kapsamları isteyin.
FHIR'da kaynakları nasıl ararım?
Sorgu parametreleriyle GET istekleri kullanın: /Patient?name=Smith&birthdate=ge1980-01-01. FHIR, değiştiricileri (:exact, :contains) ve ön ekleri (gt, lt, ge, le) destekler.
Toplu FHIR nedir?
Toplu FHIR ($export), NDJSON formatında büyük veri kümelerinin eşzamansız olarak dışa aktarılmasını sağlar. Popülasyon sağlığı, analiz ve veri ambarı için kullanılır.
FHIR sürüm kontrolünü nasıl yönetirim?
Belirli bir FHIR sürümünü (R4 önerilir) hedefleyin ve sürüme özel uç noktaları kullanın. Desteklenen sürümler ve kaynaklar için CapabilityStatement'ı kontrol edin.
FHIR'ı özel alanlarla genişletebilir miyim?
Evet, özel veri öğeleri eklemek için FHIR uzantılarını kullanabilirsiniz. Uzantıları Uygulama Kılavuzunuzda tanımlayın ve geniş çapta paylaşacaksanız HL7'ye kaydedin.
FHIR geliştirmesine hangi araçlar yardımcı olur?
Popüler araçlar arasında HAPI FHIR (açık kaynak sunucu), FHIR doğrulayıcı, Postman koleksiyonları ve API testi ve dokümantasyonu için Apidog bulunmaktadır.
