вторник, 7 марта 2017 г.

Разворачиваем собственный FHIR-сервер

Перевод оригинальной статьи блога "Hay on FHIR" от 19 октября 2016

Мне неоднократно приходилось беседовать с одной командой, которая очень хотела бы использовать clinFHIR "полноценно", т.е. для создания и редактирования профилей ресурсов (и создания "шаблонизированных" вариантов ресурсы на базе таких профилей). Для этих нужд парни уже давно используют Forge, и, если честно, лучше, чем Forge пока ничего нет, но, тогда зададимся другим вопросом: "куда загрузить (созданные нами в Forge) профили, чтобы они были доступны для clinFHIR?".




До того, как мы погрузимся в решение этого вопроса, вспомним, что нужно сделать, чтобы ClinFHIR смог работать с нашим сервером.Итак, если помните, ClinFHIR поддерживает разделение серверных ролей, которые бывают трех типов:

  1. "Дата-сервер / сервер patient-ресурсов": на нем хранятся patient-ресурсы и другие ресурсы, которые не являются conformance-ресурсами. На таком сервере хранятся ресурсы, используемые для представления непосредственно данных о здоровье и описания инфраструктуры и участников системы здравоохранения (например, ресурсы "practitioner" - (практикующий) врач, ресурсы "organization" - медицинская организация).
  2. "Conformance-сервер" (также его теперь называют Registry) хранит ресурсы тиипа "StructureDefinition", описывающие профили и расширения ресурсов, "NamingSystem" и некоторые другие.
  3. "Терминологический сервер" хранит ресурсы типа "ValueSet" (справочники) и выполняет набор команды, связанный с работой со справочниками (например, $expand, т.е. развертку наборов значений). Терминологический сервер может использоваться ClinFHIR для заполнения значениями элементов интерфейса (например, выпадающих меню) записями из справочника (ValueSet).
Обратите внимание: все описанное выше касается только clinFHIR и не является обязательным требованием стандарта. ClinFHIR поддерживает и подход, при котором "инфраструктурные" ресурсы хранятся отдельно, чтобы их можно было использовать в связке с различными дата-серверами.

Не забывайте, что это всего-лишь "виртуальные роли", т.е. их может выполнять, если необходимо, один физический сервер. На скриншоте ниже показаны настройки ClinFHIR: в качестве Patient/Data-сервера используется сервер Public HAPI STU-3 server, в качестве conformance-сервера используется сервер Грэма (Grahames STU-3 server), его же мы используем и в качестве терминологический сервера. (Важно: все 3 сервера должны поддерживать одну и ту же версию стандарта FHIR).



Разделение ролей серверов может влиять на процесс создания ресурсов: как правило, пользователь создает не менее двух типов ресурсов, следовательно и хранить их придется на двух типах fhir-серверов. Ресурсы "StructureDefinition" (т.е. "профили" и "описания расширений") размещают на conformance-сервере , а valueSet-ресурсы хранят на терминологическом сервере.

Итак, мы решили "заиметь" собственную инфраструктуру для работы с профилями ресурсов. В первую очередь развернем один или несколько серверов, разделяющих между собой поддерживаемые ClinFHIR роли (помните, мы же собираемся работать именно ClinFHIR?). Сделаем это с помощью одного приложения, разработанного нашими канадскими друзьями, кстати, авторами той самой библиотеки HAPI. Это приложение с интерфейсом командной строки, по факту полноценный бесплатный fhir-сервер, поддерживающий работу с HAPI-библиотекой. Можно даже сказать, что это такая программная обертка или оболочка для библиотеки HAPI.

Особенно подчеркну, что разворачиваемый нами сервер будет использоваться только для тестирования - никакой защиты не будет! Ни в коем случае не загружайте какие-либо персональные медицинские данные на этот сервер. Если же вы в действительности захотите использовать этот fhir-сервер, вам придется самостоятельно позаботиться о его защите. Пока этот вопрос мы просто опустим.

Разберем процесс развертывания FHIR-сервера пошагово. Условимся о том, что вы, скорее всего или сами неплохо владеете командной строкой или знаете кого-то, кто при необходимости вам поможет.
Развернем виртуальный сервер в облаке: Я предпочитаю DigitalOcean, т.к. весь процесс занимает всего несколько минут, а тарифная сетка очень гибкая (от 5$/месяц, хотя, исходя из нужного объема памяти, лучше выбрать тариф 20$/месяц, за который вы получите уже 2Гб.) Заплатив 20 долларов, мы обзавелись виртуальным сервером с Ubuntu, IP-адресом. Нам доступен также один из двух вариантов контроля доступа к серверу - с помощью ввода пароля и по сертификату SSL. Обратите внимание, что на сервере должна быть предустановлена Java 8!
Авторизуемся на сервере используя командную строку и SSH-соединение:

ssh root@clinfhir.com
Обратите внимание, что на этом этапе мы входим в систему под root'ом. Это не совсем безопасно, но на данном этапе мы пытаемся как можно большое упростить наши действия, а, значит, безопасностью можно "слегка" пренебречь. Загрузим HAPI CLI-приложение, о котором речь шла ранее, на сервер. Подходящее место на сервере - директория "/opt". Загрузим в нее файлы выполнив следующие команды (воспользуемся wget-ом):
cd /opt

wget https://github.com/jamesagnew/hapi-fhir/releases/download/v2.0/hapi-fhir-2.0-cli.zip
Вторая команда загружает на сервер вторую версию (v2) приложения в папку /opt (более актуальная версия может быть позднее доступна на странице загрузки HAPI). Распакуем загруженный файл:
unzip hapi-fhir-2.0-cli.zip
Теперь мы готовы запустить сервер. Я воспользовался следующей командой, которая должна сработать, хотя, иногда, с java приходится повозиться:
java -jar hapi-fhir-cli.jar run-server
Если все пройдет хорошо, мы увидим сообщение, что теперь у нас есть рабочий dstu2 fhir-сервер. Конечная точка сервера, принимающая запросы: [ip]/baseDstu2:8080

Что, если нам нужен именно STU-3-совместимый сервер? Или другой порт? Эти параметры сервера можно конфигурировать: предусмотрены специальные ключи для соответствующих команд, а сами команды можно подсмотреть на странице документации HAPI. Следующая команда запустит сервер в режиме совместимости с STU-3 и переведет сервер в фоновый режим (т.е. после закрытия соединения он продолжит работу):

nohup java -jar hapi-fhir-cli.jar run-server -f dstu3 --allow-external-refs &
(Обычно я создаю небольшой скрипт, чтобы не печатать все команды вручную)

Небольшое исправление в моей статье, на которую мне указал Philip Scott: в конце команды нужно добавить ключ "- allow-external-refs", иначе приложение не будет обрабатывать ресурсы с ссылками на внешние объекты.

Обратите внимание: можно развернуть STU-2 или STU-3 совместимый сервер, но крайне нежелательно настраивать его на работу одновременно с другими STU-2 и STU-3 серверами (узнал об этом на горьком опыте).

Пока наш сервер пуст, поэтому, если мы планируем использовать его в качестве conformace-сервера или терминологического сервера, придется загрузить на него набор стандартных ресурсов. Это легко делается следующим образом:

Откроем новое SSH-соединение, перейдем в директорию, где установлен HAPI-сервер, и введем следующую команду:

hapi-fhir-cli upload-definitions -t http://localhost:8080/baseDstu3 
или
java -jar hapi-fhir-cli.jar upload-definitions -t http://localhost:8080/baseDstu3
Не забудьте заменить ‘http://localhost:8080/baseDstu3’ url-ом вашего собственного сервера. С помощью этой команды мы загрузим все conformance-ресурсы (StructureDefinition, ValueSet) с основного репозитория HAPI на наш локальный сервер. Теперь можно настраивать clinFHIR на работу с нашим сервером и наконец-то работать с профилями всех стандартных типов ресурсов. Кроме того, на основании шаблонов мы также сможем генерировать "шаблонизированные" (структура которых описана профилем) экземпляры ресурсов.

Добавим наш сервер в список доступных серверов FHIR. Для этого есть специальная опция "Add server" в главном меню:


В этом окне введем данные сервера:


После ввода url'a сервера нажмите кнопку "Test", которая появится в нижней правой части формы для проверки соответствия сервера стандарту FHIR. Если сервер является валидным FHIR-сервером (т.е. в ответ на запрос возвращает Сonfromance или СapabilityStatement-ресурсы), появится кнопка "Add". Необходимо также выбрать версию FHIR (скоро приложение сможет определять поддерживаемую версию стандарта прочитав CapabilityStatement-ресурс). (Кстати, кнопка "Add Server" будет работать в браузере, в котором вы выполнили команду; ее не будет, если вы сбросите кэш настроек).

Осталось совсем немного - установить файлы SNOMED на сервер, чтобы терминологический сервер мог выполнять развертку ($expand) наборов значений SNOMED. (Весь процесс описан здесь) Не забудьте, что использование SNOMED регулируется лицензией.

Теперь сервер полностью работоспособен и теперь можно загружать на него созданные нами профили. Как обычно это можно сделать различными способами.

Самый простой способ - воспользоваться каким-нибудь REST-клиентом для копирования файлов профилей. Подойдет REST-клиент с пользовательским интерфейсом (например, POSTman): выберем файлы ресурcов в клиенте и загрузим их. Подойдет и клиент CURL, в котором все команды выполняются из командной строки.

Выполним команду в CURL:

curl http://fhir.hl7.org.nz/baseDstu2/StructureDefinition/ohCondition --upload-file ohCondition.structuredefinition.xml
Эта команда загрузит файл ohCondition.structuredefinition.xml в текущую директорию FHIR-сервера - http://fhir.hl7.org.nz/baseDstu2/StructureDefinition/ohCondition

(Я предусмотрительно написал shell-скрипт для пакетной загрузки файлов на сервер и сохранил его в папке с файлами. Не забудьте сделать скрипт исполняемым!)

Если вы пользуетесь GitHub, создайте локальную копию файлов, клонировав репозиторий и загрузочный скрипт командой "git pull".


Только не попадитесь на следующем: когда вы загружаете ресурс на HAPI-сервер, но будет проводить проверку, чтобы все ресурсы (на которые ссылается загружаемый ресурс) уже были сервере. Если ему не удастся разрешить все зависимости, в загрузке будет отказано. (Лично я не уверен, что так должно быть, но пока все работает именно так). На практике же для нас это означает, что необходимо соблюсти определенный установленный порядок загрузки (его то и можно прописать в одном загрузочном shell-скрипте):

  • Наборы значений (ValueSets), на которые ссылается какой-либо из ресурсов (если ваш сервер будет использоваться в качестве терминологического сервера),
  • StructureDefinitions, который описывает расширения ресурсов,
  • StructureDefinitions, которые описывают профили ресурсов.
(Another possible ‘gotcha’ is to make sure that Forge generates snapshots in the profiles…)

Комментариев нет:

Отправить комментарий