RC-API Client Development Guide

Introduction

The RC-API Specification leverages the FHIR standard to optimize compatibility and data exchange through all parts of the system architecture. This allows the core RC-API system to interact with any compliant implementation on both the client and service ends.

Features:

  • FHIR Parameters resource for API POST requests.

  • Responses are returned as FHIR OperationOutcome resources.

  • Decision support/Analytics Job Packages, domain specific collections of queries structured in a “question and answer” manner, are stored as valid FHIR Questionnaire resources. (See Note.)

  • Scripts such as Clinical Quality Language (CQL) and Natural Language Processing Query Language (NLPQL) are stored as FHIR Library resources.

  • “Questions” are “answered” by FHIR Observation resources generated by the analytics scripts.

  • The generated “answer” observations and the supporting FHIR resources from which the answer was drawn are packaged as a Results Bundle, a standard FHIR Collection Bundle which may be parsed by compatible clients.

Note: All resources are valid FHIR but currently cannot be validated against a specific profile as the related Implementation Guide has not yet been published. This only applies to the Job Package Questionnaire resource and contained extensions. The “Answer” Observations do not require a profile but one may be included in the release of the Implementation Guide for documentation purposes.

Server Request and Responses

(Note: For more details on specific end points and parameters accepted please see the appropriate section of this documentation.)

Client and backend service interaction is handled in an exclusively FHIR manner, unless other required by backends. In practice, this comes down to two main things:

  • POST bodies consist of FHIR Parameters resources.

  • Operation success and all error responses from the API are returned as FHIR OperationOutcome resources. Operation success refers to requests to the server which are operative in nature and do not expect a specific FHIR resource return.

  • Requests for a specific resource return that resource or a Bundle of that resource, presuming there was no error.

To clarify the last two items more explicitly: A request to the API for all Job Packages will return a FHIR Bundle of Questionnaire resources. A request to the API to asynchronously execute a Job Package does not expect an immediate result returned, and so an OperationOutcome is returned instead acknowledging the success or failure of the request.

Parameters

An example of a POST Body given as a FHIR Parameters resource is provided below

{
    "resourceType": "Parameters",
    "parameter": [
        {
            "name": "patientId",
            "valueString": "11364"
        },
        {
            "name": "jobPackage",
            "valueString": "DemonstrationForm"
        },
        {
            "name": "job",
            "valueString": "demographics"
        }
    ]
}

This example is part of a POST to the API endpoint which executes a Job Package based on a Patient context while restricting the execution to a single job within that Job Package. If you would like to run all jobs associated with the Job Package, you can exclude the job parameter and only POST the patientId or patientIdentifier and the jobPackage name.

Operation Outcome

As mentioned previously, OperationOutcome resources are returned whenever a request is made to the server that does not result in the return of a standard FHIR resource. The following example shows an OperationOutcome after a successful POST of a CQL script, which includes the ID of the new resource on the FHIR Server (CQF Ruler)

{
    "resourceType": "OperationOutcome",
    "issue": [
        {
            "code": "informational",
            "diagnostics": "Resource successfully posted with id 636993",
            "severity": "information"
        }
   ]
}

Job Packages

See Authoring Job Packages for this information.

Libraries

A major purpose of the design of the RC-API specification is to leverage multiple decision support/analytics languages via a common interface. HL7 Clinical Quality Language (CQL) is supported natively by the embedded CQF Ruler server, with additional support for Natural Language Processing Query Language (NLPQL) when coupled with ClarityNLP.

CQL or NLPQL scripts are stored in FHIR Library resources as a binary. The following shows an example of this using an example Library.

{
  "resourceType": "Library",
  "version": "1.0",
  "name": "cbc_panel",
  "status": "draft",
  "experimental": true,
  "type": {
    "coding": [ {
      "code": "logic-library"
    } ]
  },
  "content": [ {
    "contentType": "text/cql",
    "data": "bGlicmFyeSBjYmNfcGFuZWwgdmVyc2lvbiAnMS4wJwoKdXNpbmcgRkhJUiB2ZXJzaW9uICc0LjAuMCcKCmluY2x1ZGUgRkhJUkhlbHBlcnMgdmVyc2lvbiAnNC4wLjAnIGNhbGxlZCBGSElSSGVscGVycwoKY29kZXN5c3RlbSAiTE9JTkMiOiAnaHR0cDovL2xvaW5jLm9yZycKY29kZXN5c3RlbSAiU05PTUVEIjogJzIuMTYuODQwLjEuMTEzODgzLjYuOTYnCmNvZGVzeXN0ZW0gIlJ4Tm9ybSI6ICdodHRwOi8vd3d3Lm5sbS5uaWguZ292L3Jlc2VhcmNoL3VtbHMvcnhub3JtJwpjb2Rlc3lzdGVtICJDUFQiOiAnaHR0cDovL3d3dy5hbWEtYXNzbi5vcmcvZ28vY3B0Jwpjb2Rlc3lzdGVtICJJQ0Q5IjogJzIuMTYuODQwLjEuMTEzODgzLjYuNDInCmNvZGVzeXN0ZW0gIklDRDEwIjogJzIuMTYuODQwLjEuMTEzODgzLjYuMycKCmNvbnRleHQgUGF0aWVudAoKLy8gQ29uY2VwdCBEZWZpbnRpaW9ucwpkZWZpbmUgIndiY192b2xfY29uY2VwdCI6IENvbmNlcHQgewogICAgQ29kZSAnNjY5MC0yJyBmcm9tICJMT0lOQyIKfQpkZWZpbmUgInJiY192b2xfY29uY2VwdCI6IENvbmNlcHQgewogICAgQ29kZSAnNzg5LTgnIGZyb20gIkxPSU5DIgp9CmRlZmluZSAiaGVtb2dsb2Jpbl9tYXNzX3ZvbF9jb25jZXB0IjogQ29uY2VwdCB7CiAgICBDb2RlICc3MTgtNycgZnJvbSAiTE9JTkMiCn0KZGVmaW5lICJoZW1hdG9jcml0X3ZvbF9mcmFjX2NvbmNlcHQiOiBDb25jZXB0IHsKICAgIENvZGUgJzQ1NDQtMycgZnJvbSAiTE9JTkMiCn0KZGVmaW5lICJtY3ZfZW50X3ZvbF9jb25jZXB0IjogQ29uY2VwdCB7CiAgICBDb2RlICc3ODctMicgZnJvbSAiTE9JTkMiCn0KZGVmaW5lICJtY2hfZW50X21hc3NfY29uY2VwdCI6IENvbmNlcHQgewogICAgQ29kZSAnNzg1LTYnIGZyb20gIkxPSU5DIgp9CmRlZmluZSAibWNoY19tYXNzX3ZvbF9jb25jZXB0IjogQ29uY2VwdCB7CiAgICBDb2RlICc3ODYtNCcgZnJvbSAiTE9JTkMiCn0KZGVmaW5lICJyYmNfZW50X3ZvbF9jb25jZXB0IjogQ29uY2VwdCB7CiAgICBDb2RlICcyMTAwMC01JyBmcm9tICJMT0lOQyIKfQpkZWZpbmUgInJiY19yYXRpb19jb25jZXB0IjogQ29uY2VwdCB7CiAgICBDb2RlICc3ODgtMCcgZnJvbSAiTE9JTkMiCn0KZGVmaW5lICJwbGF0ZWxldHNfdm9sX2NvbmNlcHQiOiBDb25jZXB0IHsKICAgIENvZGUgJzc3Ny0zJyBmcm9tICJMT0lOQyIKfQpkZWZpbmUgInBsYXRlbGV0c19kd19lbnRfdm9sX2NvbmNlcHQiOiBDb25jZXB0IHsKICAgIENvZGUgJzMyMjA3LTMnIGZyb20gIkxPSU5DIgp9CmRlZmluZSAicGxhdGVsZXRzX212X2VudF92b2xfY29uY2VwdCI6IENvbmNlcHQgewogICAgQ29kZSAnMzI2MjMtMScgZnJvbSAiTE9JTkMiCn0KCi8vIFJldHJpZXZhbCBEZWZpbml0aW9ucwpkZWZpbmUgIndiY192b2wiOiBbT2JzZXJ2YXRpb246ICJ3YmNfdm9sX2NvbmNlcHQiXQpkZWZpbmUgInJiY192b2wiOiBbT2JzZXJ2YXRpb246ICJyYmNfdm9sX2NvbmNlcHQiXQpkZWZpbmUgInJiY19zbmFwc2hvdCI6ICJyYmNfdm9sIlswXQpkZWZpbmUgImhlbW9nbG9iaW5fbWFzc192b2wiOiBbT2JzZXJ2YXRpb246ICJoZW1vZ2xvYmluX21hc3Nfdm9sX2NvbmNlcHQiXQpkZWZpbmUgImhlbWF0b2NyaXRfdm9sX2ZyYWMiOiBbT2JzZXJ2YXRpb246ICJoZW1hdG9jcml0X3ZvbF9mcmFjX2NvbmNlcHQiXQpkZWZpbmUgIm1jdl9lbnRfdm9sIjogW09ic2VydmF0aW9uOiAibWN2X2VudF92b2xfY29uY2VwdCJdCmRlZmluZSAibWNoX2VudF9tYXNzIjogW09ic2VydmF0aW9uOiAibWNoX2VudF9tYXNzX2NvbmNlcHQiXQpkZWZpbmUgIm1jaGNfbWFzc192b2wiOiBbT2JzZXJ2YXRpb246ICJtY2hjX21hc3Nfdm9sX2NvbmNlcHQiXQpkZWZpbmUgInJiY19lbnRfdm9sIjogW09ic2VydmF0aW9uOiAicmJjX2VudF92b2xfY29uY2VwdCJdCmRlZmluZSAicmJjX3JhdGlvIjogW09ic2VydmF0aW9uOiAicmJjX3JhdGlvX2NvbmNlcHQiXQpkZWZpbmUgInBsYXRlbGV0c192b2wiOiBbT2JzZXJ2YXRpb246ICJwbGF0ZWxldHNfdm9sX2NvbmNlcHQiXQpkZWZpbmUgInBsYXRlbGV0c19kd19lbnRfdm9sIjogW09ic2VydmF0aW9uOiAicGxhdGVsZXRzX2R3X2VudF92b2xfY29uY2VwdCJdCmRlZmluZSAicGxhdGVsZXRzX212X2VudF92b2wiOiBbT2JzZXJ2YXRpb246ICJwbGF0ZWxldHNfbXZfZW50X3ZvbF9jb25jZXB0Il0="
  } ]
}

Scope of a Library

While it is up to the developer of a Job Package and its related libraries to define the scope of an individual library, in most contexts it is preferred that a single library address a specific area of inquiry. The library above is a CBC Panel Library (“cbc_panel”) which is focused on common queries related to a standard complete blood count laboratory panel. This allows each library to be, if feasible and appropriate, a modular piece of a Job Package that can be reused between multiple Job Packages. In this example, queries related to white blood cell or red blood cell count are common across many conditions/domains. Other common use examples would include basic patient demographics, vital signs, or social determinants of health.

Version Control

Library resources should be version controlled to ensure that there is not a breaking issue in a Job Package if scripts are changed. This should is done through the Library.version element rather than relying on server specific meta tags.

Result Bundles and Answer Observations

As previously mentioned, RC-API returns results in a Result Bundle. The Result Bundle is a FHIR-conformant Bundle with type collection that contains the “answers” to “questions” represented as Answer Observations. Along with the Answer Observations are the supporting FHIR resources that lead to the creation of the Answer Observations.

Note

Supporting resources are created using information returned via the analytics services (e.g. CQL and NLPQL evaluation). This means that the information contained in these resources are limited by what information is returned via the analytics services, and may not be the complete FHIR resource found on the original FHIR server. The supporting resources do contain the original resource ID and a custom identifier to indicate that they were created by RC-API

Answer Observations

A typical “simple” Answer Observation is shown below. This “simple” Answer Observation contains a single return value that would not have any associated FHIR Resources with it, this example being finding the Patient’s gender. This Answer Observation contains:

  • A generated UUID in Observation.id

  • A status of final

  • A category of survey

  • A code with the question concept defined in the jobPackage

  • A subject with a reference to the Patient

  • An effectiveDateTime where in this case, is going to the current datetime

  • A valueString with the “answer” to the “question”

Example “Simple” Answer Observation
{
     "resourceType": "Observation",
     "id": "fd1c7e32-ff07-4bc8-86cc-df94ca18d55c",
     "status": "final",
     "category": [
         {
             "coding": [
                 {
                     "code": "survey",
                     "display": "Survey",
                     "system": "http://terminology.hl7.org/CodeSystem/observation-category"
                 }
             ]
         }
     ],
     "code": {
         "coding": [
             {
                 "code": "2000000005",
                 "system": "urn:gtri:heat:form:SyphilisRegistry"
             }
         ]
     },
     "effectiveDateTime": "2022-04-11T14:53:42.381162",
     "subject": {
         "reference": "Patient/46529"
     },
     "valueString": "male"
}

An example of a more “complex” and typical Answer Observation is shown below. This Answer Observation contains an “answer” to a “question” that contains supporting resources. The most notable difference is the inclusion of the focus and note fields, and the valueString being caret-delimited. This Answer Observation contains the following:

  • A generated UUID in Observation.id

  • A status of final

  • A category of survey

  • A code with the question concept defined in the jobPackage

  • An effectiveDateTime where it’s pulled from the supporting resource

  • A subject with a reference to the Patient

  • A focus to any supporting resources that are also included in the Result Bundle

  • A note field that contains the sourceNote from the Tuples defined in the CQL or NLPQL

  • A valueString with the “answer” to the “question” (in a caret delimited format which is explained in Value in Observation.valueString)

Example “Complex” Answer Observation
 {
     "resourceType": "Observation",
     "id": "c9b14163-f8f2-4535-b5d1-19ea233ce575",
     "status": "final",
     "category": [
         {
             "coding": [
                 {
                     "system": "http://terminology.hl7.org/CodeSystem/observation-category",
                     "code": "survey",
                     "display": "Survey"
                 }
             ]
         }
     ],
     "code": {
         "coding": [
             {
                 "system": "urn:gtri:heat:form:SyphilisRegistry",
                 "code": "2000000008"
             }
         ]
     },
     "effectiveDateTime": "2022-01-14T00:00:00",
     "subject": {
         "reference": "Patient/46529"
     },
     "focus": [
         {
             "reference": "Observation/31045347"
         }
     ],
     "note": [
         {
             "text": "2022-01-14T00:00:00^http://loinc.org^20507-0^Reagin Ab [Presence] in Serum by RPR^Reactive"
         }
     ],
     "valueString": "2022-01-14T00:00:00^http://loinc.org^20507-0^Reagin Ab [Presence] in Serum by RPR^Reactive"
 }

Value in Observation.valueString

Structured Data Source (i.e. CQL)

While the FHIR Observation value is capable of handling multiple data types, structured data for the output Bundle is collapsed into a single string in order to provide simple and fast access to the returned data in a common format. If the value (Observation.valueString) contains carets (^), it’s considered structured in the following formats (each number in { } indicates the meaning of value.):

Format 1: {1}^{2}^{3}
Format 2: {0}^{1}^{2}^{3}^{4}
Format 3: {0}^{1}^{2}^{3}^{4}^{5}
Format 4: {0}^{1}^{2}^{3}^{4}^{5}^{6}

{0}: datetime (in ISO Date format)
{1}: system
{2}: code
{3}: display
{4}: additional value (could be a string or decimal)
{5}: unit if {4} is numeric Quantity.
{6}: display if {4} is system and {5} is code (for a CodeableConcept)

All {#} are optional. If any of them are empty or null, it should have no data, but the position should be intact. For example, if {1} is not available for the coded value (format 1), it should be “^{2}^{3}”.

Format Details:

  • Format 1: Coded value in system^code^display.

  • Format 2: Coded value with datetime. The datetime should be in ISO Date format (yyyy-MM-ddTHH:MM:SS)

  • Format 3: Coded value with datetime and additional value. If the additional value is string, then {5} is not required. If {4} is numeric, then {5} should be the unit. (i.e. a quantity)

Unstructured Data Source (i.e. NLPQL)

Observation.valueString with unstructured data (i.e. from NLP services) will not follow these conventions. As of the publishing of this documentation, there is only one possible combination for a valueString that contains carets. Its as follows::

Value Extraction: {1}^{2}
{1}: Term for which value is being extracted
{2}: Value capatured by the task