Что это вообще

FHIR (Fast Healthcare Interoperability Resources) — стандарт HL7 для хранения и обмена медицинскими данными так, чтобы разные системы (больница, лаборатория, страховая, мобильное приложение) могли друг друга понимать.

Представь: пациент сходил к врачу, потом сдал кровь в лаборатории, потом ему выписали лекарство. Это три разных события в трёх разных системах. Каждая система пишет данные по-своему — у больницы свои поля в БД, у лаборатории свои, у аптеки свои. Когда нужно собрать полную картину про пациента — кто-то должен переводить между форматами.

FHIR говорит: «давайте все будем хранить медицинские данные в одном формате — наборе карточек, связанных между собой ссылками». Каждая карточка — JSON-документ описывающий одну вещь.

Спецификация: https://www.hl7.org/fhir/

Сегодня в продакшене у нас FHIR R4 — детальнее в fhir-versions (R4 / R5 / R6, design-trends, наши планы миграции).

Карточки и связи между ними

Каждая карточка — отдельный объект с уникальным ID. Карточки бывают разных типов (resource types):

  • Patient — карточка пациента (имя, дата рождения, контакты)
  • Observation — карточка результата измерения (глюкоза = 5.5 ммоль/л)
  • Condition — карточка диагноза (диабет 2 типа)
  • MedicationRequest — карточка назначения (метформин 500мг 2р/день)
  • Practitioner — карточка врача
  • Organization — карточка организации (лаборатория, клиника)

И ещё ~140 других типов под разные сценарии — какие именно бывают типы, как они сгруппированы по модулям спецификации (Foundation / Clinical / Financial / Specialized), смотри fhir-resource-categories-overview.

Конкретный пример

Иван сдал кровь, по результатам поставили диагноз, назначили лечение. В FHIR это будет 5 карточек, связанных ссылками:

                       Patient
                      ┌─────────────┐
                      │ id: pat-001 │
                      │ name: Иван  │
                      │ born: 1980  │
                      └──────┬──────┘
                             │ subject
        ┌────────────────────┼────────────────────┐
        ▼                    ▼                    ▼
   Observation           Condition         MedicationRequest
   ┌──────────────┐     ┌────────────┐    ┌──────────────┐
   │ id: obs-001  │     │ id: cnd-1  │    │ id: med-1    │
   │ code: глюк.  │     │ code: T2DM │    │ med: метф.   │
   │ value: 5.5   │     │ recorder:→ │    │ requester:→  │
   │ performer: → │     │   prac-1   │    │   prac-1     │
   │   org-1      │     └────────────┘    └──────────────┘
   └──────┬───────┘
          │ performer
          ▼
    Organization                        Practitioner
   ┌──────────────┐                    ┌──────────────┐
   │ id: org-1    │                    │ id: prac-1   │
   │ name: ЛабX   │                    │ name: Иванов │
   └──────────────┘                    └──────────────┘

Стрелки — это ссылки (тип Reference) между карточками. У Observation.subject — указание на пациента. У Condition.recorder — кто записал диагноз. У MedicationRequest.requester — кто назначил.

Каждая карточка может быть отдельно прочитана через REST API:

GET /Patient/pat-001        → JSON карточки пациента
GET /Observation/obs-001    → JSON карточки лабораторного результата
GET /Patient/pat-001/$everything  → Bundle со всеми карточками пациента

Сравнение с реляционной БД

SQLFHIR
таблица patientresourceType Patient
строка в таблицеодна JSON-карточка
id колонкаполе id карточки
foreign key patient_idReference на Patient/pat-001
JOIN patients ON observations.patient_idпройти по Observation.subject к Patient
схема таблицыresource definition (StructureDefinition)

Ключевые отличия:

  • Схема публичная и стандартная. В SQL каждая больница придумывает свою; в FHIR — единая, опубликована HL7.
  • Хранение как JSON-документы. Не таблицы с колонками, а отдельные документы. Любой FHIR-сервер раздаёт их через стандартный REST API.
  • Ссылки через URL. Связи между ресурсами — не числовые id, а строки вида Patient/pat-001. Можно ссылаться на пациента в чужой системе через absolute URL.
  • Schema-driven validation. FHIR-сервер сам проверяет валидность ресурса при write (cardinality, required fields, value sets); SQL обычно делает только тип-чек и базовые constraints.

Что делает FHIR полезным

  1. Один формат для всех. Если ты пишешь Patient — он одинаково выглядит у больницы в США, лаборатории в РФ, мобильного приложения на Android. Можно exchange’иться без переводчиков.
  2. REST API стандартный. GET /Patient/123 работает одинаково в любой FHIR-системе. Не надо изучать каждый custom API.
  3. Эволюция через расширения. Если стандартного поля не хватает — есть механизм extension для custom-добавлений. Downstream-consumer’ы могут их игнорировать без поломки (см. fhir-profiling).

Что читать дальше

Зная что есть карточки и связи между ними — можно углубляться по нужде:

  • Содержимое одной карточки (cardinality, primitive types, DataTypes, references, meta, extensions, choice types, bundles) — fhir-resource-elements
  • Конкретные виды карточек в нашем pipeline:
  • Версии стандарта R4 / R5 / R6 — fhir-versions
  • Профилирование (как мы конкретизируем стандарт под себя) — fhir-profiling
  • Meta-ресурсы (StructureDefinition / ValueSet / etc — те ресурсы, которые описывают сам стандарт) — fhir-conformance-resources
  • FSH — DSL для авторства profiles — fsh
  • Tooling (codegen, validators, clients) — fhir-tooling · fhir-code-generation
  • Realm-IGs (что добавляется поверх base FHIR в США / РФ) — us-core · rucore
  • Provenance + meta.tagfhir-meta-tagging · fhir-resource-origin-and-lifecycle (как мы трекаем origin: chat / survey / document-import)
  • LOINCloinc (главная codesystem для лабораторных)