SMART on FHIR 範例程式

用瀏覽器原生 JavaScript 寫的 SMART on FHIR app,沒有打包工具、沒有框架、不需要 Node.js。 出自 2026 iThome 鐵人賽的一個系列, 每個資料夾對應一篇文章。程式碼在 GitHub

下面每一天都是一份完整可跑的專案,點進去就會在你的瀏覽器裡跑起來, 跟 clone 下來自己起靜態伺服器跑的是同一份程式碼,行為沒有差別。

連著跑好幾天的話,換一天之前先重新整理並清掉分頁的 session。 授權結果存在 sessionStorage,同一個網域底下共用, 後面那天會直接沿用前一天那張 token,而每一天要的 scope 並不相同。 最容易看出來的是 day14:沿用 day12 的 token 就沒有 refresh token, 那一天的手動換 token 會換不成。

這是教學範例,不是醫療服務。 所有範例連的都是 SMART Health IT 的公開測試 sandbox,裡面的病人由 Synthea 合成,不是去識別化的真人資料。

那個 sandbox 是共用的,任何人寫進去的東西大家都看得到。 絕對不要放入真實病人資料,一筆都不要,包括拿真人的姓名或生日去測試。

標著「會寫入」的那幾天會真的把資料寫進去,而且不會自動清掉。 測完請自己送一個 DELETE /Observation/{id} 把它刪掉。

目前有哪些

  1. day04

    開發環境準備不需授權

    連上公開 FHIR server,畫面顯示連線成功與拿到的病人參照。

  2. day06

    SMART Discovery 與能力探索不需授權

    .well-known/smart-configuration 問出授權端點與 token 端點。

  3. day09

    從頭跑完一次授權

    自己寫 PKCE 與授權碼流程,走完一趟 standalone 授權,console 印出 access token 與 patient id。

  4. day12

    解析 Launch Context

    換用 fhirclient 函式庫,同一件事從一百多行變成三十行不到,畫面從 patient id 變成病人姓名與生日。

  5. day14

    Token 的生命週期

    多一顆按鈕手動換 token,再把用過的那張 refresh token 送一次,看伺服器收不收。

  6. day15

    第一個 SMART app

    把 Patient 資源整理成姓名、性別、生日、病歷號四個欄位,畫面第一次有東西可以給人看。

  7. day16

    呈現臨床資料(一)

    把血壓與體重從 Observation 挖出來畫成雙 y 軸趨勢圖。同一種資源兩種結構,取值要分開寫。

  8. day17

    呈現臨床資料(二)

    把病況與用藥列成兩張表,處理 CodeableConcept 的三層取值順序與臨床狀態欄位。

  9. day18

    寫回 FHIR會寫入

    把自己量的血壓存回伺服器。POST 回 201,但 LocationETag 在瀏覽器裡讀不到。測完記得把那筆刪掉。

  10. day19

    處理錯誤會寫入

    六顆按鈕各觸發一種失敗,看伺服器實際回什麼。401 回的是純文字不是 OperationOutcome,無條件呼叫 response.json() 會在那裡炸掉。

  11. day20

    搜尋與分頁會寫入

    一路照抄 next 跟完 10 頁 94 筆。自己算 offset 在這台行不通,它的 next 換成了一串 _getpages 的暫存 id。

  12. day21 與 day22

    兩家醫院會寫入

    兩家各自一組 clientIdscope,端點問出來之後快取一天。拿錯 token 打另一家不會回 403,它回 200 加一份標著 SUBSETTED 的殘缺資料。

  13. day24

    跨院合併時間軸

    兩家各自授權,合併成一條 402 筆的時間軸,每一筆都標來源。日期不要切字串,slice(0, 10) 切的是 UTC 日期,台灣早上八點前的紀錄會顯示成前一天。

系列還在進行中,後面的資料夾會隨文章發布陸續加進來。 中間跳過的那幾天沒有各自的專案,原因寫在 README 裡。

想自己跑

不必改任何一行就能跑,檔案裡填好的 sandbox 設定是一串無狀態的編碼,誰拿去用都成立。 想換成自己的病人或情境,到 SMART Health IT Launcher 產生一組貼回去即可,細節看 README。