把一些實作IG的經驗分享給大家。
2021年3月16日 星期二
2021年2月8日 星期一
CDS Hooks 實作驗證
實作這塊,有點不好意思,程式碼還是不方便公布。簽了保密,還是保守點。除非老闆說可以。所以,這邊只好用別人的東西來展示。
CDS Services
CDS Hooks Sandbox
FHIR Server
原則上EMR應該會配有FHIR Server。但我們測試是用Sandbox,不會有FHIR Server,我們得找一個。我是用Sandbox建議的FHIR Server:https://launch.smarthealthit.org/v/r4/fhir 。選哪個都無所謂,但建議還是以R4為準。
首先你要確認你所選擇的FHIR Server有支援,你在Prefetch Template所叫用的FHIR Resource。否則,你怎麼死的都不知道。
- Get {based url}/{Resource} : 看看回來什麼東西。注意如果有Bundle回來,但筆數為0,表示這台Server有支援此Resource,只是現在沒有資料。
- Get {based url}/metadata:這個會回傳CapabilityStatement。在rest/resource,就會列出所有支援的Resource。其實,這個CapabilityStatement還有其他非常重要的資訊。就舉個最重要的吧。他們會把OAuth資訊放在這。這超出本系列的範圍了,但這真的很重要。
Patient ID
進行驗證程序
設定FHIR Server
將系統建議的FHIR Server版次改為R4即可。記得要按Next。設定Patient
加入CDS Services
2021年2月1日 星期一
CDS Hooks - 規範 - 5
終於來到最無聊的最後階段「Feedback」。
前言
在CDS Response Object中,有提到Suggestion,其實他應是由CDS Client端產生一個按鈕,並以POST方式帶Feedback物件回給CDS Server。這邊就得要注意,CDS Client的使用者,到底是按哪一個suggestion按鈕。還要注意,CDS Services有很多個,根據規範書的內容每一個CDS Service都要有自己的Feedback。
POST {baseUrl}/cds-services/{serviceId}/feedback
Feedback Object
當初CDS Response物件中Card.uuid的內容值。
outcome
CDS Client對此card的態度。兩個選項accepted或者overridden。
acceptedSuggestions
如果outcome是選擇accepted,那就得回傳到底是接收哪個(些)suggestion(無論是單選還是多選)。其結構很簡單,就是當初suggesion的uuid。
overrideReason
如果outcom是選擇overridden的話,可以提供理由。其結構為OverrideResaon物件:
outcomTimestamp
最後給這個回應押一個時間戳記。這是必要欄位。
這邊高度依賴CDS Client的支援程度而定。不過,身為CDS Service必須位自己提供的建議作後續支援服務的機制。因為這個過程可能不是只有一個來回,有可能是數個CDS Service的組合方能完成一個臨床實務上的決策循環。
2021年1月31日 星期日
CDS Hooks - 規範 - 4
今天討論「CDS Response」
CDS Response
Response的前置作業
- 檢核Post 資料正確性。也就是說,傳回來的Hook跟當初規定的是否一樣。
- 要解析fhirAuthorization。你要設計好流程,到底還要再跟FHIR Server要什麼東西。因為Access Token一般都是有時間限制(當然,還會有個Refresh Token的機制)。另外一點就是,他會有Scope的問題,就是Resource.Interactions。
- 要解析prefetch的內容。這塊要小心。一般而言,若Read,原則上你要什麼Resource就會回給你什麼Resource。若你是用Search,那就會是Bundle,要再進一步解析entry才是你想要的Resource。
- 取你CDS真正要的資料進行運算處理,然後得到結果。這個結果才是用來組出Response Object的資料。
Response Object
Card Object
uuid
這個是可選欄位。若你有處理到feedback階段的話,那這個就很重要。在C#有個GUID物件,很簡單處理。
summary
這個是必要欄位。將你的結果簡單描述。字串長度要小於140個字元(我實作時有踢到這個鐵板) 。
detail
結果的詳細說明。若是Debug階段,一些訊息就放在這(別像我,以為summary是必要就放在那兒,結果是Bug的Bug)。
indicator
說明這個結果的重要程度。目前支援有info、warning與critical。理想上,應該是不同程度畫面要有所區別,但是要看CDS Client要不要實作。
source
這是用來宣告版權的,為必要欄位。其結構為:(不多加解釋,coding結構就是FHIR的資料型態)
suggestions
這個整個card的核心,卻是Optional。他的內容是suggestion物件陣列。用來描述,CDS所提供的可採取行動之建議。其結構為:
其中action欄位是實際描述「當CDS Client接受這個Suggestion時要如何處理」。其結構為:
處理的方式不外乎create、update與delete(怎麼沒有retrive?啊你前面在幹嘛?)。resource就是處理的對象。就是Resource啦。這裡要注意你要處理的Resource,當初的Scope都要宣告到。不過,還是得看CDS Client有沒有支援啦(坦白說,FHIR的真還在發展中,就是因為發展中,那還不趕快跟上)。貼個EPIC支援的給各位參考。(剪圖關係未能全部)
selectionBehavior
如果你有suggestion欄位,那這個欄位就是必要。他只有兩種選項at-most-one,單選。與any,多選。哈~還是要看CDS Client有沒有支援啦。
overrideReasons
當CDS Client不接受你任何suggestion時,你可以用這個欄位讓他選擇不接受的理由。他是coding的陣列。還是一樣,要看CDS Client要不要支援。
links
這是提供給CDS Client一些建議網站或者APP實用的。他是Link物件陣列。其結構為:
範例
官方範例提供參考
{ "cards": [ { "summary": "Example Card", "indicator": "info", "detail": "This is an example card.", "source": { "label": "Static CDS Service Example", "url": "https://example.com", "icon": "https://example.com/img/icon-100px.png" }, "links": [ { "label": "Google", "url": "https://google.com", "type": "absolute" }, { "label": "Github", "url": "https://github.com", "type": "absolute" }, { "label": "SMART Example App", "url": "https://smart.example.com/launch", "type": "smart", "appContext": "{\"session\":3456356,\"settings\":{\"module\":4235}}" } ] }, { "summary": "Another card", "indicator": "warning", "source": { "label": "Static CDS Service Example" } } ] }
在實作的過程這個階段很痛苦。因為每一個CDS Client的支援程度與方式不盡相同,甚至容錯能力也不同。
2021年1月28日 星期四
CDS Hooks - 規範 - 3
複習一下,CDS的實作流程有四個階段的規範,「Discovery」、「Request CDS」、「CDS Response」與「Feedback」。今天討論Request CDS。
Request CDS
CDS Client 呼叫 --> CDS Server實作
Endpoint: POST {baseURL}/cds-services/{service.id}
Request Object
叫用這個service所規定的hooks標準。大部分都是patient-view。
hookInstance
這是由CDS Client產生的UUID碼,他必須需Globally unique。CDS Server端,每一個hookInstance都是單一事件,都得單獨處理。我這次實作比較像寫範例,所以這個值我沒有記錄下來。其實,回應訊息時也不會用到。
fhirServer
這個是CDS Client告訴CDS Server我的FHIR Server在哪裡。他是一個完整路徑。(切到資源)
fhirAuthorization
這個有點複雜是OAuth 2.0內容。主要是給你Access Token,讓你可以直接向CDS Client的FHIR Server抓取資料。不過,都得要事先宣告Scope,其流程沒有那麼簡單。也不是CDS Client都會給你。
context
hooks是規範,只有描述需要哪些鍵值欄位。CDS Client就把這次POST資料實際鍵值內容放在這裡。如果Client採用Prefetch方式,已經這個內容不重要。但是,採fhirAuthorization的話,這個就很重要。每次來回的資料總得是同一個病人吧。
prefetch
這的內容很重要。他就是CDS Server用prefetch template告知CDS Client要準備的FHIR內容。CDS Server端在解析的時候要小心。當初你可以同時要了好幾條不同的Resource。另外,你可能走Search 方式,那你收到的可能是Bundle回來的東西,解析時要小心。
Request 範例
這是CDS Client發出的資料(部分)
至於這個sandbox介面後續會介紹。網址先給各位了:https://sandbox.cds-hooks.org/
CDS Server端就根據自己所需要資料到prefetch裡的FHIR Resource去抓囉。
其實,如果CDS Client如果沒有給你fhirAuthorization的資訊,那就隱含告訴你,去他們的FHIR Server抓資料無須Access Token。
至於要怎麼解析,程式面的問題,應該會找適當時間來寫寫。如果沒有保密問題的話。
至於CDS要怎麼運用資料,那就超出本系列的範圍了。
CDS Hooks - 規範 - 2
進入無聊的階段,卻是實作最重要的階段。
實作CDS的整個過程,可以粗分「Discovery」、「Request CDS」、「CDS Response」與「Feedback」四個階段。(先把OAuth的部分屏除)
Discovery
CDS Client呼叫 <--> CDS Server實作
Endpoint: GET {baseURL}/cds-services
Response Object:
註:
- 想看完整有Swagger文件:Swagger Editor。
- 都是JSON格式。
- 注意Type是Primitive type, Object還是Array。
hook
這個欄位是宣告兩端要共同遵守的鍵值變數組合(Context)。最常見的就是patient-view,他要求雙方有userId(R)、patientId(R)與encounterId(O)。這些鍵值欄位會以「prefetch tokens」的形式應用於prefetch欄位(後敘)中。所謂prefetch tokens就是用{{ }}包覆鍵值變數。
title
這個欄位可有可無,純粹用來給人看,由CDS Client決定要不要去呈現他。
description
這個欄位反而是必要欄位,用來描述這個Hook服務的主要任務是什麼。
id
這個欄位非常重要,而且要小心設計。這個會是URL的一部分,也就是呼叫這個服務的路徑。所以,他必須要唯一。{baseUrl}/cds-services/{id}。
prefetch
這個欄位雖為Optional,卻是非常重要的欄位。CDS Server端告知CDS Client端,若要使用此服務,請你要提供哪些FHIR Resource。這個欄位內容的表達方式,有一個專有名稱為「Prefetch Template」是否能看懂且會用,又要用得好,就是看你FHIR的功力了。後面會專節說明。
Discovery 範例
Prefetch Template
CDS Hooks的Prefetch Template他就是FHIR read與search的機制。(另外支援的機制在後面規範會提到)所以,懂FHIR愈多,就能寫個漂亮的Prefetch Template,CDS Server端能要來的資料就更精確。























