We are excited to announce that you can now launch your SMART apps in your Logica Sandbox instance using app link cards in the CDS-Hooks Sandbox!
Complete Flow
Please see CDS Hooks Integration for details.
Setting It Up
To set up this scenario,
- either create a new, or use an existing Logica Sandbox instance,
- create, host, and register your SMART app,
- make sure your SMART app can launch successfully from your Logica Sandbox instance
- create and host your CDS services
Launching Your App
Referring to CDS Hooks Integration, your app link cards will now be functional! To see this,
- click on the link in your app link card in the CDS Hooks sandbox,
- as shown in the diagram above, your app will be launched using your Logica sandbox instance as the issuer (iss=My Sandbox),
- your app will complete the SMART launch flow, discovering the auth server, requesting authorization, and finally receiving an access token to your Logica Sandbox!
Would you like your SMART on FHIR app to be optimized in production? We have launched a guide which walks you through how to integrate best practices into your app. The guide describes three ways to increase the marketing aspects of your application and to ease production implementation. The guide is composed of three parts:
- Creating a marketing page
- Social media link previews
- Manifest files
- Patient information banners
You can access the guide through this link: SMART App Best Practices.
In the previous Terminology & Profile Support blog post I introduced the Logica Terminology Server and gave step-by-step instructions on some common use cases including:
- Utilizing FHIR Terminology Services on the Logica Terminology Server for common SMART on FHIR app development tasks
- Validating instance data for non-profiled FHIR resources using the
$validate
operation - Retrieving
StructureDefinition
resources describing the FPAR resources currently in development
If you haven't read through part one, you can access it at Logica Sandbox - Terminology & Profile Support (part 1).
In part two I will continue by showing how to validate profiled instance data using the $validate
operation on the Logica Sandbox. The profiles we'll focus on are those coming from the us-core validation pack, for FHIR version STU3 (3.0.1). These profiles have been uploaded to the Logica Terminology Server, which can be found at:
https://api-v5-stu3.logicahealth.org/stu3/open
Request Format
Our request to validate looks just like it did in our previous examples, the important distinction is the use of the Meta.profile field to indicate that this instance data conforms to a profile. The value of the Meta.profile field should be a reference to the StructureDefinition.url of the StructureDefinition resource which defines this instance data.
For our examples, we'll be using http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient, which is the us-core profile for the Patient resource. You can read the docs for this profile, or you can query the structure definition file directly from the Logica Terminology Server:
sand/StructureDefinition?url=http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient
Response
omitted due to size
Putting this all together, we can formulate the $validate
request as follows:
POST https://api-v5-stu3.logicahealth.org/stu3/open/Patient/$validate --- REQUEST BODY --- { "resourceType": "Parameters", "parameter": [ { "name": "resource", "resource": { "resourceType": "Patient", "meta": { "profile": [ "http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient" ] }, "identifier": [ { "use": "usual", "type": { "coding": [ { "system": "http://hl7.org/fhir/v2/0203", "code": "MR" } ] }, "system": "urn:oid:1.2.36.146.595.217.0.1", "value": "12345", "period": { "start": "2001-05-06" }, "assigner": { "display": "Acme Healthcare" } } ], "active": true, "gender": "male", "name": [ { "use": "official", "family": "Chalmers", "given": [ "Peter", "James" ] }, { "use": "usual", "family": "Yep", "given": [ "Jim" ] }, { "use": "maiden", "family": "Windsor", "given": [ "Peter", "James" ], "period": { "end": "2002" } } ] } } ] }
Response:
Profiled Instance Data Validation
Now that we know what the request looks like, lets take a closer look at some validation examples. For starters, we'll validate the patient General Purpose Example from the official Patient Resource FHIR docs. It looks like this:
POST https://api-v5-stu3.logicahealth.org/stu3/open/Patient/$validate --- REQUEST BODY --- { "resourceType": "Parameters", "parameter": [ { "name": "resource", "resource": { "resourceType": "Patient", "meta": { "profile": [ "http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient" ] }, "id": "example", "identifier": [ { "use": "usual", "type": { "coding": [ { "system": "http://hl7.org/fhir/v2/0203", "code": "MR" } ] }, "system": "urn:oid:1.2.36.146.595.217.0.1", "value": "12345", "period": { "start": "2001-05-06" }, "assigner": { "display": "Acme Healthcare" } } ], "active": true, "name": [ { "use": "official", "family": "Chalmers", "given": [ "Peter", "James" ] }, { "use": "usual", "given": [ "Jim" ] }, { "use": "maiden", "family": "Windsor", "given": [ "Peter", "James" ], "period": { "end": "2002" } } ], "telecom": [ { "use": "home" }, { "system": "phone", "value": "(03) 5555 6473", "use": "work", "rank": 1 }, { "system": "phone", "value": "(03) 3410 5613", "use": "mobile", "rank": 2 }, { "system": "phone", "value": "(03) 5555 8834", "use": "old", "period": { "end": "2014" } } ], "gender": "male", "birthDate": "1974-12-25", "_birthDate": { "extension": [ { "url": "http://hl7.org/fhir/StructureDefinition/patient-birthTime", "valueDateTime": "1974-12-25T14:35:45-05:00" } ] }, "deceasedBoolean": false, "address": [ { "use": "home", "type": "both", "text": "534 Erewhon St PeasantVille, Rainbow, Vic 3999", "line": [ "534 Erewhon St" ], "city": "PleasantVille", "district": "Rainbow", "state": "Vic", "postalCode": "3999", "period": { "start": "1974-12-25" } } ], "contact": [ { "relationship": [ { "coding": [ { "system": "http://hl7.org/fhir/v2/0131", "code": "N" } ] } ], "name": { "family": "du Marché", "_family": { "extension": [ { "url": "http://hl7.org/fhir/StructureDefinition/humanname-own-prefix", "valueString": "VV" } ] }, "given": [ "Bénédicte" ] }, "telecom": [ { "system": "phone", "value": "+33 (237) 998327" } ], "address": { "use": "home", "type": "both", "line": [ "534 Erewhon St" ], "city": "PleasantVille", "district": "Rainbow", "state": "Vic", "postalCode": "3999", "period": { "start": "1974-12-25" } }, "gender": "female", "period": { "start": "2012" } } ] } } ] }
Response:
If we were to validate this patient instance data against the base FHIR specification for the Patient resource then it would pass. Since we've claimed this resource confroms to us-core, the server is checking the instance data against the StructureDefinition for the us-core patient and we see an error. This specific error is telling us that every name attribute MUST include a value in the family
field, however our instance data does not. We could fix this by adding a family name (see below) and the resource would pass validation.
{ "use": "usual", "family": "Windsor", "given": [ "Jim" ] }
Let's trim down the patient resource we are tyring to validate and see if we can get some more errors.
POST https://api-v5-stu3.logicahealth.org/stu3/open/Patient/$validate --- REQUEST BODY --- { "resourceType": "Parameters", "parameter": [ { "name": "resource", "resource": { "resourceType": "Patient", "meta": { "profile": [ "http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient" ] }, "id": "example", "name": [ { "use": "usual", "given": [ "Jim" ] }, { "use": "maiden", "family": "Windsor", "period": { "end": "2002" } } ], "telecom": [ { "use": "home" }, { "system": "phone", "value": "(03) 5555 6473", "use": "work", "rank": 1 }, { "system": "phone", "value": "(03) 3410 5613", "use": "mobile", "rank": 2 }, { "system": "phone", "value": "(03) 5555 8834", "use": "old", "period": { "end": "2014" } } ], "birthDate": "1974-12-25", "address": [ { "use": "home", "type": "both", "text": "534 Erewhon St PeasantVille, Rainbow, Vic 3999", "line": [ "534 Erewhon St" ], "city": "PleasantVille", "district": "Rainbow", "state": "Vic", "postalCode": "3999", "period": { "start": "1974-12-25" } } ], "contact": [ { "relationship": [ { "coding": [ { "system": "http://hl7.org/fhir/v2/0131", "code": "N" } ] } ], "name": { "family": "du Marché", "_family": { "extension": [ { "url": "http://hl7.org/fhir/StructureDefinition/humanname-own-prefix", "valueString": "VV" } ] }, "given": [ "Bénédicte" ] }, "telecom": [ { "system": "phone", "value": "+33 (237) 998327" } ], "address": { "use": "home", "type": "both", "line": [ "534 Erewhon St" ], "city": "PleasantVille", "district": "Rainbow", "state": "Vic", "postalCode": "3999", "period": { "start": "1974-12-25" } }, "gender": "female", "period": { "start": "2012" } } ] } } ] }
Response:
In this example we've violated just about all cardinality constraints defined by the us-core patient profile. Notice that the severity of these messages is error
. This indicates that the instance data is in violation of the profile and would not be considered compliant. There are also warning
and information
severities, which are meant to notify of best practice, but don't necessarily mean the instance data is in violation.
As a final example, let's look at the us-core smokingstatus profile for the Observation resource. I've taken their example instance data, and deleted the resource.code
field, let's try to validate it:
POST https://api-v5-stu3.logicahealth.org/stu3/open/Observation/$validate --- REQUEST BODY --- { "resourceType": "Parameters", "parameter": [ { "name": "resource", "resource": { "resourceType": "Observation", "id": "some-day-smoker", "meta": { "profile": [ "http://hl7.org/fhir/us/core/StructureDefinition/us-core-smokingstatus" ] }, "status": "final", "category": [ { "coding": [ { "system": "http://hl7.org/fhir/observation-category", "code": "social-history", "display": "Social History" } ], "text": "Social History" } ], "subject": { "reference": "Patient/example", "display": "Amy Shaw" }, "issued": "2016-03-18T05:27:04Z", "valueCodeableConcept": { "coding": [ { "system": "http://snomed.info/sct", "code": "428041000124106", "display": "Current some day smoker" } ], "text": "Current some day smoker" } } } ] }
Response:
In the response we can see a list of issues, most of the classified as information
or warning
. The last two issues are error
level and are a result of deleting the LOINC smoking-status code, these indicate that the resource instance does not actually conform to the indicated profile.
Validating Resource Without "Parameters" Resource
If a user wants to validate a resource without embedding in it as a parameter in a Parameters FHIR resource, that is also an option. Here's an example of a heart rate Observation example:
{ "resourceType": "Observation", "id": "heart-rate", "meta": { "profile": [ "http://hl7.org/fhir/StructureDefinition/heartrate" ] }, "status": "final", "category": [ { "coding": [ { "system": "http://hl7.org/fhir/observation-category", "code": "vital-signs", "display": "Vital Signs" } ], "text": "Vital Signs" } ], "code": { "coding": [ { "system": "http://loinc.org", "code": "8867-4", "display": "Heart rate" } ], "text": "Heart rate" }, "subject": { "reference": "Patient/example" }, "performer": { "reference": "Practitioner/example" }, "effectiveDateTime": "1999-07-02", "valueQuantity": { "value": 44, "unit": "beats/minute", "system": "http://unitsofmeasure.org", "code": "/minute" } }
Limitations of Logica Sandbox Validation
In the FHIR Validation spec, there is a mention of being able to pass a custom profile via the url (https://www.hl7.org/fhir/validation.html#op). The call would look something like this:
POST [base]/Observation/$validate?profile=http://hl7.org/fhir/StructureDefinition/heartrate
Although this approach would be convenient, HAPI, the FHIR server off of which the Logica servers are built, does not support this functionality.
Another possible approach to adding a profile for validation is to implement a Parameters resource and to add a parameter in the list that states the profile url (https://www.hl7.org/fhir/operation-resource-validate.html):
{ "resourceType": "Parameters", "parameter": [ { "name": "profile", "valueUri": "http://hl7.org/fhir/StructureDefinition/heartrate" }, { "name": "resource", "resource": { ...
This, however, is also not supported by HAPI.
So for now, using the approaches described earlier (passing the profile url through the meta.profile parameter) are the only way to validate against custom profiles. We will update our documentation if/when either approach becomes available.
Conclusion
Validating instance data through a FHIR Terminology Service like the Logica Terminology Server is a great way of ensuring data quality and interoperability. The example's we've shown have been for the us-core profiles, but should work equally well for any profiles built using the standard StructureDefinition
resources and loaded into the terminology service.