FHIR 快速跳坑指南
簡介如何使用、讀懂 FHIR ,並配合網頁表單進行互動
Lorex L. Yang(楊宇凡)<ceo@sita.tech>
Nov 25, 2019/陽明大學/FHIR 系列研習課程
About myself
• Backend developer / node.js developer
• Linux server administration
• Proxmox VE / Docker
• Web hosting service
• Open source lover
• 矽塔資訊服務有限公司 | 執行長
• 雪歐有限公司 | 技術長
• 高嘉國際餐飲股份有限公司 | 系統工程師
• 宇宙新幹線科技有限公司 | 系統工程師
• Lionfree 獅子的免費虛擬主機 | 共同創辦人
Agenda
• PART 1: 簡介
 FHIR 是什麼?可以吃嗎?
 概觀、特性、與結構
• PART 2: 文件導讀
 如何快速讀懂 FHIR Document
 資料型態與 Resource 拆解
• PART 3: 快速上手
 REST API 簡介
 如何與 FHIR Server 互動
 如何組織資料
• PART 4: 實際應用情境
 網頁表單設計簡介
 實作簡易的病患資料登錄程式
免責聲明
因為等等會有一些 Live Demo
不小心 NG 的話請別笑我QQ
…真的想笑的話,請小聲點 (噓
歡迎發問、回答 ヽ( ° ▽°)ノ
議程中會使用到的資源將會公開在這裡
https://hackmd.io/@lorex8711/rkCXQV7hr
懶的打網址的話,就直接掃 QR Code 吧!
上禮拜的議程裡面已經討論過 FHIR 的發
展
今天的議程將不再進行贅述
而是從工程角度去探討實務開發問題
FHIR 簡介
FHIR 是什麼?可以吃嗎?
Fast 快速
Healthcare 健康照護
Interoperability 互通
Resources 資源
FHIR 概觀
• 是一種新興的醫療資訊交換標準
• 由 HL7 International(國際健康資訊第七層協會)制定
• 奠基於 HL7 v2 & HL7 v3 標準
• 主要目標為
1. 促進醫療單位有效溝通醫療相關資訊
2. 廣泛應用於多種設備,包含但不限於電腦、手機、平板等裝置
重點在快速
傳統資料互通方式
資料格式不一致,無法互通
導入 FHIR 後的資料互通方式
格式一致,可以無痛互通!
So what is FHIR?
• 基本上就是一個資料模型
• 把整個醫療流程/體系中會接觸到的資料全部標準化為單一資料結構
• 支援多種不同資料格式
• 採用主流資訊實作標準
 沒醫學基礎的工程師也可以理解,很好上手
 要跟其他系統對接也很方便
• 可讀性高
 醫療人員不用懂程式設計,也能看得懂資料
• 格式嚴謹,Document 齊全且明確
• Developer Friendly ❤
Example 1
Example 2
FHIR 結構
• 對醫療人員/醫學系學生來說,
FHIR 是一種描述醫療資源/行為/數據/流程…etc 的方法
• 對開發人員/醫資or醫工系學生來說,
我們熟悉的 FHIR 事實上是一堆 Data Structure
• 每一個醫療資源/行為/數據/流程…etc 都是一個 Resource
• 依照不同的分類,FHIR 將幾個 Resource 組成一支 Module 方便檢視
文件導讀
如何快速讀懂 FHIR Document?
隨便抓一個 Resource 看一下
Resourc
e
介紹/
關聯/
使用範圍
內容、資料結構與細部說明
(重要!)
欄位值的 Reference 與限制
可被搜尋的參數清單
Resource Content
欄位名稱
對應數量 資料型態(Data
Type)
欄位定義與
規範/限制
旗標
Data Structure? Data Format? Data
Type?
• 所謂的 Data Structure(資料結構),是對一組資料組成的定義
• 而 Data Format(資料格式),則是表達這組資料的方法(例如 XML、JSON 等)
• 一個 Data Structure 可以用許多不同的 Data Format 所表示
• 一個 Resource 只有一種 Structure,但是支援多種 Data Format
• 在開發實務上,並不需要認識所有的 Data Format,僅需挑一種來用即可
• 至於 Data Type(資料型態),則是定義一項資料值的類型(例如 Number、
String、Time…etc)
Data Type
Data Type 四大類
• Simple / Primitive Types
 大多是常見且格式定義明確的資料型態
 例如 integer 是 “整數”、date 是 “日期”,兩者都有既定的格式
• Complex / General-Purpose Data types
 顧名思義比較複雜,大多由數個型態為 Primitive Type 的元素組成
 一個 Complex Type 內,甚至可以由其他 Complex Type 構成
• Metadata Types
 拿來存放 metadata 的資料型態,大多在 R4 版本仍為 Trial Use 階段
• Special Purpose Data types
 規範用於其他地方的資料型態
 例如 Reference 為指向到另一筆資料的參照,Extension 為本地化/客製化資料
Primitive
Primitive
Primitive
Complex
Complex
另外還有一個 Reference
就是剛剛看到的 Special Purpose Data Type
Reference 是對應到其他 Resource 的參
照
可以透過 ID 與其他 Resource 對應在一起
資料型態(Complex)
參照
資料型態(Primitive)
網站有提供範例,可以直接開來看
Search Parameters
• 這邊列出的是可以直接被搜尋的欄位值
• 通常這裡有的欄位會優先使用
Overview
Resource 類別(必填)
流水號
人類可讀區域
Resource 內容
Meta 資訊
擴展資料
(本地化/客製化資料)
Overview
• Resource Type
 存放 Resource 類別,為必填選項
 實務上 FHIR Server 會根據 Resource Type 去進行資料檢查,所以不能寫錯
• 流水號(id)
 為這筆 Record 在 FHIR Server 裡面的唯一識別碼,通常由 Server 端產生
 流水號為跨 Resource 共用,也就是有了 Patient/123 之後就不可能會有
Organization/123
 Resource 內的 id 跟 identifier 不一樣
 id 是目前這筆 Record 在這台 Server 內的流水號
 identifier 則是這筆 Record 的唯一識別碼,不同 Server 間可以用同一個 identifier 來定位同一筆資
料
• Meta 資訊
 為伺服器端產生的摘要資訊
 記載變更次數、最後更新時間、Profile、資料來源……等
Overview
• 人類可讀區域(text)
 記載人類可讀的摘要資訊與這筆 Record 目前的狀態
 以 XHTML 格式存在,可以直接被網頁前端 Render
• 擴展資料(extension)
 為 FHIR 中可擴展、本地化、客製化的資料
 非必填,有需要的時候自行使用即可
• Resource 內容(data)
 Resource 的資料本體,就是剛剛在文件看到的 Resource Content
 通常 Server 會針對這邊的資料進行檢查,如果有問題就會噴錯
快速上手開發
如何存取與組織 FHIR 資料?
REST API
• 當代主流的資訊交換技術,廣泛應用於軟體開發
• 充分使用 HTTP 通訊協議
• 擁有簡潔直觀的 URI,並善用了 HTTP Verb
• 透過 REST API 可以對 FHIR Server 進行各項操作(增/刪/改/查)
• 接受 FHIR 所支援的 Data Format(JSON and XML)
RESTful API 與一般 API 的比較
一般 API
• 獲取使用者資料 GET /getAllUsers
• 獲取使用者資料 GET /getUser/1
• 新增使用者資料 POST /createUser
• 更新使用者資料 GET /updateUser/1
• 刪除使用者資料 GET /deleteUser/1
RESTful API
• 獲取使用者資料 GET /users
• 獲取使用者資料 GET /user/1
• 新增使用者資料 POST /user
• 更新使用者資料 PUT /user/1
• 刪除使用者資料 DELETE /user/1
Before After
REST API 的應用情境
單一資源(例如 /Patient/1)
GET 列出該筆Resource
與其下的 Attributes
POST 在該筆Resource下
新增給定的
Attributes
PUT 使用給定的
Resource與
Attributes 取代原有
Resource(整筆替
換)
PATCH 只更新該筆
Resource下指定的
Attributes(部分更
新)
多重資源(例如 /Patient )
GET 列出該資源組裡面所
有Resources
POST 在該資源組中新增
Resource
PUT 若該資源組中無指定
Resource,則新增
(跟POST 一樣),
否則就整筆替代該
Resource
DELETE 刪除整個資源組下的
所有 Resources
REST API 使用方法
<Method> <baseURL>/<resource>/[id]{?options}
HTTP 方法 網址 目標 resource id 選
項
看不懂嗎?套個範例
GET
https://hapi.fhir.tw/baseDstu3/Observation/41123?_summary=true
HTTP Method BaseURL Resourc
e
OptionsId
透過 Postman 與 FHIR Server 互動
Postman
測試 API 的好工具
https://www.getpostman.com/
Method and URL
回應視窗
開始來玩玩看
取得所有 Patient 資料
GET https://hapi.fhir.tw/fhir/Patient
取得單一 Patient 資料
GET https://hapi.fhir.tw/fhir/Patient/1
新增一筆 Patient 資料
• POST https://hapi.fhir.tw/fhir/Patient
• Payload 如右
編輯剛剛的 Patient 資料
• PUT https://hapi.fhir.tw/fhir/Patient
• Payload 如右
刪除剛剛新增的 Patient 資料
DELETE https://hapi.fhir.tw/fhir/Patient/265
組織臨床資料,並寫入 FHIR Server
內
以 Patient 為例
範例病人資料
• 姓名:王大明
• 性別:男
• 連絡電話:0912-345-678
• 聯絡地址:高雄市小港區大馬路999號
• 資料有效狀態:YES
• 生日:84/01/01
組織資料步驟
• 判定、或取得各欄位所屬的 Resource 與 Field Name,並建一張表對應
原始欄位 原始資料 對應欄位 資料格式
姓名 王大明 Patient.name HumanName
性別 男 Patient.gender code
(male | female | other |
unknown)
連絡電話 0912-345-678 Patient.telecom ContactPoint
聯絡地址 高雄市小港區大馬路999號 Patient.address Address
資料有效狀態 Yes Patient.active boolean
生日 84/01/01 Patient.birthDate date
組織資料步驟
• 以 JSON 為例,去組織資料,暫時先不要理 Complex Type 的欄位
(紅色字體為 Complex Type 欄位,因為還沒完成所以顯示 JSON 格式不正確)
組織資料步驟
• 確認 Complex Type 內的格式內容,然後依次展開後填入
寫入資料
• POST https://hapi.fhir.tw/fhir/Patient
• Body 資料如右
• 執行結果如下
驗證:查詢剛剛新增的資料
• GET https://hapi.fhir.tw/fhir/Patient/267
應用情境實作
以臨床量測數據登錄表單為例
注意事項
• 考量到本節課程的聽眾大多是學生,因此將以最簡單的 HTML + JavaScript +
jQuery 進行實作
• 因為 Code 有點多,在這邊將會就實作架構進行簡介,有興趣的話可以把整個
Repository 抓回去慢慢讀
• 本 Demo 程式僅供參考,實務上的開發會比這個複雜的多
• 所有 Code 都可以在這裡找到,議程一開始提供的資源列表裡面也有:
 https://gitlab.sita.tech/medic/fhir-training-example
開發環境
• 選一個喜歡的文字編輯器
 用來寫程式碼,可以是文字編輯器、也可以是 IDE
 推薦使用 Visual Studio Code
 帶有正體中文界面,並且易於使用(記得安裝 Live Server 擴充元件)
• 選一個喜歡的瀏覽器
 推薦使用 Mozilla Firefox,或是 Google Chrome
 以上兩者都具有非常優良的偵錯工具,可以在開發階段協助 Debug
 不建議使用 Internet Explorer,你會踩雷踩到懷疑人生。真的堅持要用的話,請出去(誤)
• 準備一台 FHIR Server
 可以自己建,也可以使用 HAPI FHIR CLI 搭建臨時環境
 網路上也有很多公開的測試伺服器
• 安裝 Git
 大家都在用的版本控制工具,可以針對你的 Code 進行版本控制
FHIR Server
• 考量到現場環境,當場下載並開一個 HAPI FHIR Server 並不是建議的選項
以下是幾個推薦的公開測試伺服器:
• 臺灣公開測試伺服器(推薦使用)
 站點在國內,速度快,並支援 SSL 安全加密連線
 https://hapi.fhir.tw/
• UHN 公開測試伺服器
 為 HAPI FHIR 開發組織 UHN 提供的測試伺服器
 http://hapi.fhir.org/
• 其他伺服器列表,請參考:
 https://wiki.hl7.org/index.php?title=Publicly_Available_FHIR_Servers_for_testing
Features
• Patient 管理
 可以查看所有 Patient 的摘要資料清單
 可以新增單筆 Patient 資料
 在 Patient 清單上,可以點進去查看該筆 Patient 的詳細資料
• Observation 管理
 可以查看所有 Observation 的摘要資料清單
 可以新增單筆 Observation 資料
 可以在 Patient 的詳細資料頁面中,看到與該 Patient 關聯的 Observation
檔案結構
• index.html:網站進入點
• css 資料夾:存放 Bootstrap CSS 檔案
• js 資料夾:存放各式 js 檔案
 Bootstrap JS
 Popper.js
 jQuery
• js-fhir 資料夾:本次實作寫的 script
 init.js:初始化設定、動作
 config.js:設定檔
 getXXX.js:取得單筆資料
 listXXX.js:列出該 Resource 的資料清單
 uploadXXX.js:顯示並上傳表單
看起來好像很複雜
其實都是在做同一件事情
撈資料與上傳資料
• 以前在前端使用 XMLHttpRequest(XHR)進行實作
 傳統的 XHR 寫起來很麻煩,Code 也醜不拉機的
 基於 Event 的異步模型寫起來並沒有現代的 Promise、async/await 來的友好
• 現在通常改用 Fetch 來實作
 基於標準的 Promise 進行設計
 支援 async/await,搭配 ES6 的 Arrow Function 寫起來可以更簡潔美觀
 語法簡潔、並且更加語意化,Code 可讀性高
 符合關注分離,不將輸入、輸出等混雜在同一個 Object 裡
• 還是不懂?
 Fetch 寫起來比較簡潔、比較好學!學他就對了!
XHR vs Fetch
XHR Fetch
Fetch 撈資料與丟資料
GET
POST
可以自己塞 Options
DOM 操作
• 點擊按鈕後,需要動態呈現表單
• 抓到資料後,需要動態產生表格、資料內容
(動態產生 DOM 元素)
• 通常以原生 JS 操作 DOM、或透過 jQuery 進行操作
 原生 JS 執行速度較快,缺點是 Code 比較長、實作相對麻煩
 jQuery 語法較簡潔,學習門檻較低,功能強大
範例程式碼中常用的 jQuery 操作
• 透過 element id 選取 DOM 元素
 let content = $('#content');
• 清空該 DOM 元素下所有節點
 content.empty();
• 將新的 DOM 元素附加在目前的 DOM 元素底下(從尾端插入)
 content.append(html);
• 將新的 DOM 元素附加在目前的 DOM 元素底下(從前端插入)
 content.prepend(html);
• 刪除選取的 DOM 元素
 content.remove();
知道怎麼操作資料與 DOM 後
剩下的就只是拼湊了
列出資料清單
listPatient.js / listObservation.js
清空畫面並顯示 Loading 資訊
使用 Fetch 撈資料
建立表格標題
遍歷陣列
並動態新增資料至表格中
判斷是否有下一頁
然後顯示下一頁按紐
上傳資料-顯示表單
uploadPatient.js / uploadObservation.js
清空畫面
顯示表單
上傳資料-送出表單資料
uploadPatient.js / uploadObservation.js
清除警告訊息
檢查資料
有漏填或填錯的就顯示警告訊息
組織 FHIR 規範的資料結構
使用 Fetch 送資料給 FHIR
Server
並顯示回傳結果
顯示資料細項
getPatient.js / getObservation.js
清空畫面並顯示 Loading 資訊
使用 Fetch 撈資料
顯示資料內容
畫面展示
補充:如果你是寫後端的…
示範以 node.js 撰寫程式進行介接
既然都支援 REST 了,直接串就好
• 創建空資料夾,然後 npm init
$ npm init
• 安裝 dependencies
$ npm i -S axios
• 新增 payload.json,先把 payload 寫進去
• 新增 main.js,寫入主程式
node.js 簡易示範程式碼
• payload.json
node.js 簡易示範程式碼
• main.js
Q&A
感謝聆聽

陽明大學/FHIR 快速跳坑指南