-
Notifications
You must be signed in to change notification settings - Fork 70
Order Select Service
Goal: To display a card containing a suggestion to switch the selected medication order to Aspirin 81 MG Oral Tablets through text and the suggestions field. If the medication selected is our recommended prescription, then affirm the clincian's choice via text.
See documentation on the EHR calling a CDS Service: https://cds-hooks.org/specification/current/#calling-a-cds-service
See documentation on the CDS Service response: https://cds-hooks.org/specification/current/#cds-service-response
As we defined in our discovery endpoint, we have a CDS Service set up to listen for the order-select
hook to be invoked. Once this hook
is invoked, the EHR may decide to call upon our order-select-example
CDS Service to provide support. Similar to the patient-view-example
service,
this service should also be invoked via a POST
HTTP request with a request body containing context for the service call. And as you may have noticed in the discovery endpoint,
the order-select-example
service does not request a prefetch from the EHR. Instead, this service will rely just on the context
property
in the request body that may contain a FHIR resource for the order selected.
An example request body might look similar to this format:
{
"hookInstance" : "abc234",
"hook" : "order-select",
"fhirServer" : "https://sb-fhir-dstu2.smarthealthit.org/api/smartdstu2/open",
"context": {
"patientId": "SMART-1288992",
"user" : "Practitioner/example",
"selections": [
"MedicationOrder/order-123"
],
"draftOrders": {
"resourceType": "Bundle",
"entry": [
{
"resource": {
"resourceType": "MedicationOrder",
"dateWritten": "2018-05-11",
"status": "draft",
"patient": {
"reference": "Patient/SMART-1288992"
},
"medicationCodeableConcept": {
"text": "Acetaminophen 80 MG Chewable Tablet [Tylenol]",
"coding": [
{
"display": "Acetaminophen 80 MG Chewable Tablet [Tylenol]",
"system": "http://www.nlm.nih.gov/research/umls/rxnorm",
"code": "731370"
}
]
},
{ ... snipped for brevity ... }
}
}
]
}
}
}
In the example request body above, notice that the context of the medication selected by the clinician is in two places within the context
property. First, the selections
property contains the reference for the selected order and second, the draftOrders
property takes the form of a FHIR bundle with an entry array of the single medication selected, but in a real-world scenario could potentially contain other orders previously selected.
Once we have this FHIR resource, we can parse it to check if the clinician is prescribing our suggested medication. But
first, let's define our route to this CDS Service.
app.post('/cds-services/order-select-example', (request, response) => {
...
});
Again, we define in our application a POST
route to the order-select-example
CDS Service endpoint. And we will use the request
object
to parse the body of incoming POST
requests. Now let's look at the logic to return our cards inside that function block.
const draftOrder = request.body.context.draftOrders.entry[0].resource;
const selections = request.body.context.selections;
if (['MedicationRequest', 'MedicationOrder'].includes(draftOrder.resourceType) && selections.includes(`${draftOrder.resourceType}/${draftOrder.id}`)
&& draftOrder.medicationCodeableConcept) {
const responseCard = createMedicationResponseCard(draftOrder);
response.send(JSON.stringify(responseCard, null, 2));
}
response.status(200);
Above, we should immediately check for the context
property in the request body, similar to how we checked the prefetch
property on our patient-view-example
service.
Once we store that information in some variables, we should check to see if a medication is even being selected in the first place.
Note that the EHR could invoke the CDS Service at any given time, and we want to make sure our response for returning a card is appropriate only when a medication is selected.
If a medication is not selected, our service should simply return a HTTP 200
status code without any response body.
If a medication is selected, by checking for the presence of a medicationCodeableConcept
property in the MedicationOrder
resource,
then we can start to create a card response in JSON format like we have been doing. Let's dig in and see how we create that card in the
createMedicationResponseCard
function.
function createMedicationResponseCard(context) {
const providerOrderedMedication = context.medicationCodeableConcept.coding[0].code;
if (providerOrderedMedication === '243670') {
return {
cards: [
{
summary: 'Currently prescribing a low-dose Aspirin',
indicator: 'info'
}
]
};
} else {
let newMedicationOrder = context;
newMedicationOrder.medicationCodeableConcept = {
text: 'Aspirin 81 MG Oral Tablet',
coding: [
{
display: 'Aspirin 81 MG Oral Tablet',
system: 'http://www.nlm.nih.gov/research/umls/rxnorm',
code: '243670'
}
]
};
return {
cards: [
{
summary: 'Reduce cardiovascular risks, prescribe daily 81 MG Aspirin',
indicator: 'warning',
suggestions: [
{
label: 'Switch to low-dose Aspirin',
actions: [
{
type: 'create',
resource: newMedicationOrder
}
]
}
],
source: {
label: 'Learn more about Suggestions',
url: 'https://cds-hooks.org/specification/current/#cds-service-response'
}
}
]
};
}
}
In this function, we handle two cases.
- If the code for this medication matches the code for our recommended Aspirin medication (code: 243670), return a card affirming their choice via plain text
- If the code for this medication does not match the code for our recommended Aspirin, return a card containing text of the benefits of Aspirin and
a suggestion to switch to the recommended Aspirin. Additionally, we will include a
source
property link to the spec to learn more about suggestions
Let's look more closely at case 2 since it is more involved. This logic occurs in the else
block of the conditional logic. First, we create a copy of the first object in the context
property of the
request body (which was passed in as a parameter) named newMedicationOrder
. With this copy, we can mutate the medicationCodeableConcept
property to contain our recommended Aspirin medication.
We have now created a copy of a MedicationOrder
resource that we ideally want the clinician to prescribe for the patient.
We can take this resource copy and put it in the suggestions
field accordingly to match the CDS Hooks spec (see documentation above for CDS Service Response).
And similar to how we included a link in the links
field of the card response, we can put the URL to the CDS Hooks spec in the source
field of the card. Finally,
we should indicate this suggestion is of higher priority than our previous cards since we are suggesting a medication change, so the indicator field should be set to warning
, and now we can return this card.
Once this function returns the appropriate card back to the main POST
body for this service, we can return the response in JSON format to the EHR.
Next step: Testing Your Services