CDS Hooks are services called by CDS Clients (typically Electronic Health Record Systems (EHRs) or other health information systems). They implement a "hook"-based pattern for invoking decision support from within a clinician's workflow.
Smile CDR implements Version 1.1 of the CDS Hooks Specification.
The Smile CDR CDS Hooks Module simplifies the effort for creating CDS Hooks. All you need to do is create a method that accepts a CdsServiceRequestJson
parameter and returns a CdsServiceResponseJson
value and annotate this method with the @CdsService
annotation. This annotation, and the Json classes and all their subcomponents are available in the open-source project called cdr-api-public
. Any FHIR resources in requests and responses are automatically serialized into hapi-fhir FHIR resource instances for you so they are easy to work with within your code.
In addition to simplifying the effort to build CDS Hooks, the Smile CDR CDS Hooks module also provides the following:
The Smile CDR CDS Hooks module provides a couple of powerful Auto-Prefetch features:
allowAutoFhirClientPrefetch
is set to true
in the @CdsService
annotation on your CDS Service method, then
before calling your method, Smile CDR will compare the prefetch elements declared by your service method in
the @CdsService
annotation to the prefetch elements included within the CdsServiceRequestJson
REST request and if
it detects any are missing, then Smile CDR will use the FHIR endpoint authorization details included within
the fhirAuthorization
element in the request to automatically add them to the prefetch before calling your method.null
is not considered to be missing. CDS Hooks clients set a
prefetch value to null
to indicate that this prefetch data is known to not exist).fhirServer
is included in the request
@CdsService
annotation on the service method has allowAutoFhirClientPrefetch = true
, then Smile CDR will
perform a FHIR REST call to that fhirServer
endpoint to fetch the missing data.fhirServer
endpoint itself to retrieve the
missing data.source
for the @CdsServicePrefetch
.
Smile CDR will attempt to use the source
strategy for the query instead of following the order above.The diagram below shows how CDS Hooks work. The box in grey contains customer code, which is code that you write.
A CDS Hooks implementation is packaged as a Java JAR file that contains several key components:
A CDS Hooks class contains annotated service and feedback methods. One CDS Hooks class can contain any number of these methods. A CDS Hooks service method is annotated with the @CdsService
annotation and a CDS Hooks feedback method is annotated with the @CdsServiceFeedback
annotation. The "value" of these annotations corresponds to the id of the CDS Hooks service. For example:
A method annotated with @CdsService(value="example-service")
is acccessed at a path like https://example.com:8888/cds-services/example-service
A method annotated with @CdsServiceFeedback(value="my-service")
is acccessed ata path like https://example.com:8888/cds-services/my-service/feedback
.
A very basic example is shown below:
package ca.cdr.endpoint.cdshooks.module;
import ca.uhn.hapi.fhir.cdshooks.api.CdsService;
import ca.uhn.hapi.fhir.cdshooks.api.CdsServiceFeedback;
import ca.uhn.hapi.fhir.cdshooks.api.CdsServicePrefetch;
import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceFeedbackJson;
import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceIndicatorEnum;
import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceRequestJson;
import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceResponseCardJson;
import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceResponseCardSourceJson;
import ca.uhn.hapi.fhir.cdshooks.api.json.CdsServiceResponseJson;
import org.hl7.fhir.r4.model.Patient;
public class ExampleCdsService {
@CdsService(value = "example-service",
hook = "patient-view",
title = "Greet a patient",
description = "This service says hello to a patient",
prefetch = {
@CdsServicePrefetch(value = "patient", query = "Patient/{{context.patientId}}")
})
public CdsServiceResponseJson exampleService(CdsServiceRequestJson theCdsRequest) {
Patient patient = (Patient) theCdsRequest.getPrefetch("patient");
CdsServiceResponseJson response = new CdsServiceResponseJson();
CdsServiceResponseCardJson card = new CdsServiceResponseCardJson();
card.setSummary("Hello " + patient.getNameFirstRep().getNameAsSingleString());
card.setIndicator(CdsServiceIndicatorEnum.INFO);
CdsServiceResponseCardSourceJson source = new CdsServiceResponseCardSourceJson();
source.setLabel("Smile CDR");
card.setSource(source);
response.addCard(card);
return response;
}
@CdsServiceFeedback("example-service")
public String exampleServiceFeedback(CdsServiceFeedbackJson theFeedback) {
return "{\"message\": \"Thank you for your feedback dated " + theFeedback.getOutcomeTimestamp() + "!\"}";
}
}
Both of these example methods accept a single json instance parameter (CdsServiceRequestJson
and CdsServiceFeedbackJson
respectively). Alternatively, these methods can accept a single String parameter in which case the CDS Hooks module will string-encode the instance before calling the method.
This mandatory class is a Spring Framework Annotation-based Application Context Config class. It is characterized by having the @Configuration
annotation on the class itself, as well as having one or more non-static factory methods annotated with the @Bean
method, which create instances of your providers (as well as creating any other utility classes you might need, such as database pools, HTTP clients, etc.).
This class must instantiate a bean named cdsServices
:
cdsServices
bean method should return a List<Object>
of classes that contain @CdsService
and/or @CdsServiceFeedback
annotated methods.The following example shows a Spring Context Config class that registers the CDS Hooks example above.
@Configuration
public class TestServerAppCtx {
/**
* This bean is a list of CDS Hooks classes, each one
* of which implements one or more CDS-Hook Services.
*/
@Bean(name = "cdsServices")
public List<Object> cdsServices(){
List<Object> retVal = new ArrayList<>();
retVal.add(new ExampleCdsService());
// add other CDS Hooks classes...
return retVal;
}
}
This section outlines considerations when building your CDS Hooks classes.
In order to build your Smile CDR CDS Hooks, you will need the annotation and json classes on your path. Currently, this is accomplished by adding the cdr-api-public-*.jar file to your build classpath. This jar file can be found in your smilecdr/lib folder. In the future, this jar will be published to a central repository and available as a maven dependency.
See Library Support for details concerning libraries available on the classpath where your CDS Hooks classes are loaded.
The Spring Context Config class and your CDS Hooks classes must all be packaged up in a normal Java JAR file. No third party libraries should be packaged with your code.
If you are using Apache Maven as your build system, this just means you should use a normal project with a packaging of jar
.
Once you have created a JAR with your CDS Hooks in it, this JAR should be placed in the customerlib/
directory of the Smile CDR installation, and Smile CDR should be restarted. You will then want to create a new module configuration as follows:
IBaseResource
objects
according to this FHIR Version.CDS Hooks methods have access to the underlying authenticated user session if needed. See Security Attributes for more information.
See Exceptions for details concerning exceptions and error management within CDS Hooks classes.
Per Version 1.1 of the CDS Hooks Specification, a list of all registered services is available at a path like https://example.com:8888/cds-services
. As a convenience, swagger REST documentation is provided at the root of the endpoint: https://example.com:8888/
.
A sample CDS Hooks project is available at the following links: