Chuyển đến nội dung chính

Bài 15: FHIR Subscriptions và Real-time Notifications

Topic-based Subscriptions (R5), SubscriptionTopic, Subscription resource, notification channels (rest-hook, websocket, email), notification types (handshake, heartbeat, event-notification), filters, payload content. Thực hành cấu hình Subscription trên HAPI FHIR Server.

🏗️ Kiến trúc — Bài 15 Bài 15: FHIR Subscriptions và Real-time Notifications

HL7 FHIR - Chuẩn Dữ liệu Y tế từ Cơ bản đến Nâng cao

Phần 5: Tích hợp, Messaging và Security

xdev.asia

Xem bản video

1. Subscriptions trong FHIR R5

FHIR R5 giới thiệu Topic-based Subscriptions — thay thế hoàn toàn cơ chế cũ của R4. Cho phép hệ thống nhận thông báo real-time khi data thay đổi.


┌──────────┐      Subscribe       ┌──────────┐
│  Client  │ ──────────────────▶ │  FHIR    │
│  (EMR,   │                     │  Server  │
│  app)    │ ◀────────────────── │          │
│          │    Notification      │          │
└──────────┘                     └──────────┘

2. SubscriptionTopic

SubscriptionTopic định nghĩa "chuyện gì có thể subscribe" — events, triggers, filters có sẵn.

{
  "resourceType": "SubscriptionTopic",
  "id": "topic-encounter-admission",
  "url": "http://hospital.vn/fhir/SubscriptionTopic/encounter-admission",
  "title": "Encounter Admission",
  "status": "active",
  "description": "Thông báo khi có bệnh nhân nhập viện mới",
  "resourceTrigger": [
    {
      "description": "Encounter mới được tạo hoặc chuyển status sang in-progress",
      "resource": "http://hl7.org/fhir/StructureDefinition/Encounter",
      "supportedInteraction": ["create", "update"],
      "queryCriteria": {
        "current": "status=in-progress&class=http://terminology.hl7.org/CodeSystem/v3-ActCode|IMP",
        "resultForCreate": "test-passes",
        "resultForDelete": "test-fails"
      }
    }
  ],
  "canFilterBy": [
    {
      "description": "Filter theo location (khoa)",
      "resource": "Encounter",
      "filterParameter": "location"
    },
    {
      "description": "Filter theo service provider",
      "resource": "Encounter",
      "filterParameter": "service-provider"
    }
  ],
  "notificationShape": [
    {
      "resource": "Encounter",
      "include": [
        "Encounter:subject",
        "Encounter:participant"
      ]
    }
  ]
}

3. Subscription Resource

{
  "resourceType": "Subscription",
  "id": "sub-admission-notify-001",
  "status": "requested",
  "topic": "http://hospital.vn/fhir/SubscriptionTopic/encounter-admission",
  "reason": "Nhận thông báo nhập viện khoa Tim mạch",
  "filterBy": [
    {
      "resourceType": "Encounter",
      "filterParameter": "location",
      "value": "Location/loc-cardiology"
    }
  ],
  "channelType": {
    "system": "http://terminology.hl7.org/CodeSystem/subscription-channel-type",
    "code": "rest-hook"
  },
  "endpoint": "https://ehr-app.hospital.vn/api/webhooks/fhir-notifications",
  "heartbeatPeriod": 60,
  "timeout": 60,
  "contentType": "application/fhir+json",
  "content": "id-only",
  "maxCount": 10
}

Channel Types

ChannelMô tảUse case
rest-hookHTTP POST đến endpointServer-to-server integration
websocketWebSocket connectionReal-time UI, dashboards
emailEmail notificationAlert cho clinicians
messageFHIR Messaging ($process-message)Tích hợp messaging systems

Content Levels

LevelMô tả
emptyChỉ notification header, không có resource data
id-onlyResource ID + type, client tự fetch
full-resourceChứa đầy đủ resource trong notification

4. Notification Types

Handshake Notification

Gửi khi subscription được tạo, xác nhận endpoint hoạt động.

{
  "resourceType": "Bundle",
  "type": "subscription-notification",
  "entry": [
    {
      "resource": {
        "resourceType": "SubscriptionStatus",
        "type": "handshake",
        "subscription": {
          "reference": "Subscription/sub-admission-notify-001"
        },
        "topic": "http://hospital.vn/fhir/SubscriptionTopic/encounter-admission",
        "eventsSinceSubscriptionStart": "0"
      }
    }
  ]
}

Event Notification

{
  "resourceType": "Bundle",
  "type": "subscription-notification",
  "entry": [
    {
      "resource": {
        "resourceType": "SubscriptionStatus",
        "type": "event-notification",
        "subscription": {
          "reference": "Subscription/sub-admission-notify-001"
        },
        "topic": "http://hospital.vn/fhir/SubscriptionTopic/encounter-admission",
        "eventsSinceSubscriptionStart": "5",
        "notificationEvent": [
          {
            "eventNumber": "5",
            "focus": {
              "reference": "Encounter/enc-new-001"
            },
            "additionalContext": [
              {"reference": "Patient/patient-new-001"}
            ]
          }
        ]
      }
    },
    {
      "fullUrl": "https://fhir-server.example.com/fhir/r5/Encounter/enc-new-001",
      "resource": {
        "resourceType": "Encounter",
        "id": "enc-new-001",
        "status": "in-progress"
      }
    }
  ]
}

Heartbeat Notification

Gửi định kỳ để xác nhận subscription còn hoạt động, ngay cả khi không có events.

5. Subscription Lifecycle


requested → active → error → off
    │          │        │
    │          │        └── Server tạm dừng sau nhiều lần gửi thất bại
    │          └── Nhận handshake thành công
    └── Client POST Subscription

6. Thực hành Subscriptions trên HAPI FHIR

# 1. Kiểm tra SubscriptionTopics có sẵn
curl -s https://hapi.fhir.org/baseR5/SubscriptionTopic | jq '.entry[].resource.url'

# 2. Tạo Subscription
curl -X POST https://hapi.fhir.org/baseR5/Subscription \
  -H "Content-Type: application/fhir+json" \
  -d '{
    "resourceType": "Subscription",
    "status": "requested",
    "topic": "http://example.org/FHIR/SubscriptionTopic/admission",
    "channelType": {"code": "rest-hook"},
    "endpoint": "https://your-webhook.example.com/fhir-notify",
    "contentType": "application/fhir+json",
    "content": "id-only"
  }'

# 3. Kiểm tra status
curl -s https://hapi.fhir.org/baseR5/Subscription/sub-id | jq '.status'

# 4. Tạo Encounter để trigger notification
curl -X POST https://hapi.fhir.org/baseR5/Encounter \
  -H "Content-Type: application/fhir+json" \
  -d '{"resourceType":"Encounter","status":"in-progress","class":[{"coding":[{"code":"IMP"}]}],"subject":{"reference":"Patient/123"}}'

7. Tổng kết

  • SubscriptionTopic — Server định nghĩa events có thể subscribe

  • Subscription — Client đăng ký nhận thông báo, chọn channel, filter, content level

  • Channels — rest-hook (phổ biến nhất), websocket, email, message

  • Notification types — handshake, heartbeat, event-notification

  • Thay thế hoàn toàn cơ chế Subscription cũ của R4 (criteria-based)