Test server for executing FHIR-based Electronic Clinical Quality Measures (eCQMs).
Clone the source code:
git clone https://github.com/projecttacoma/deqm-test-server.gitInstall dependencies:
npm installBuild:
npm run buildUnit tests can be running using the following npm command:
npm run testThis test server makes use of MongoDB, a cross-platform document-oriented database program.
Follow the MongoDB Community Edition installation guide for your platform, and follow the commands for running MongoDB on your machine.
This server uses Redis in order to use the bee queue Node.js queue library. To install with Homebrew, run the following command:
brew install redisTo launch Redis, run:
brew services start redisTo verify the Redis server is running, ping it with:
redis-cli pingYou should receive the output PONG.
This test server can be run with Docker by calling docker-compose up --build.
Debugging with terminal input can be facilitated with stdin_open: true and tty: true added to the service specification for the service you want to debug. You can then attach to the image of interest using docker attach <imagename>. If you're unsure of the image name, use docker ps to find the image of interest.
Once MongoDB is running on your machine, run the npm start command to start up the FHIR server at localhost:3000. The server can also be run in "watch" mode with npm run start:watch and in "debug" mode by running NODE_ENV=development npm start.
The built version of the server can be run by executing node build/index.js.
DEQM test server offers optional FHIR resource validation using the Inferno FHIR Validator. The FHIR Validator acts as middleware on all PUT and POST requests that attempt to write data to the server. To set this up locally, pull and run the Inferno FHIR Validator docker image using docker run -p 4567:4567 infernocommunity/fhir-validator-service. Then start up the test server using VALIDATE=true VALIDATOR_HOST=localhost VALIDATOR_PORT=4567 npm run start. These environment variables can be changed in the .env file as well to prevent lengthy start-up commands.
For ease of testing, it is recommended to download Insomnia API Client and Design Tool for sending HTTP requests to the server and Robo 3T as a GUI for viewing the Mongo database.
When sending requests, ensure that the "Content-type": "application/json+fhir" header is set. For sending POST/PUT requests, ensure that the "X-Provenance" is populated with a valid JSON object with the resourceType key set to "Provenance".
The following npm commands can be used to set up the database:
npm run db:setupcreates collections for all the valid FHIR resource typesnpm run db:deletedeletes all existing collections in the databasenpm run db:resetruns both of the above, deleting all current collections and then creating new, empty collections- To upload all the ecqm-content-r4-2021 measure bundles,
git clonethe ecqm-content-r4-2021 repo into the root directory of thedeqm-test-serverrepository. Runnpm run upload-bundles. This runs a script that uploads all the measure bundle resources to the appropriate Mongo collections. - The full CLI function signature of
upload-bundlesscript isnpm run upload-bundles [dirPath] [searchPattern]ORnpm run upload-bundles --test. The command can be run more dynamically by specifying adirPathstring which represents the path to a repository that contains the desired bundles for upload.searchPatternis a string which is used as a regex to filter bundle files for upload by file name. Example:npm run upload-bundles connectathon/fhir401/bundles/measure "^EXM124.*-bundle.json". Using the--testoption assumes defaults for these options, but also addsGroup,Organization, andPractitionerresources for more extensive testing.upload-bundles-testruns the upload with the--testoption and is provided for convenience.
The test server supports the following operations: create, read, update, and delete, search, and transaction. See the FHIR CRUD Operations documentation for more information.
The test server's Measure searching capabilities support searches by name, version, both, or neither.
GET http://localhost:3000/4_0_1/Measure/returns all Measures currently in the databaseGET http://localhost:3000/4_0_1/Measure?name=NAMEreturns all Measures in the database with nameNAMEGET http://localhost:3000/4_0_1/Measure?NAME&version=VERSIONreturns all Measures in the database with nameNAMEand versionVERSION
The test server's resource searching capabilities support searches by identifier.
GET http://localhost:3000/4_0_1/RESOURCETYPE/?identifier=IDreturns bundle entries of resource typeRESOURCETYPEthat have the identifierID. Errors are thrown when an identifier is not included. An empty searchset is returned if the identifier cannot be found in the database.
This operation calculates measure(s) for a given patient or set of patients. Currently, individual and population measure reports are supported. Subject-list measure reports are not yet supported.
Required parameters include:
periodStart: start of the measurement periodperiodEnd: end of the measurement periodsubject: subject is required for anindividualreportTypeand is the subject for which a measure will be calculatedmeasureId: Required if the measure ID is not specified in the URL. May also be a list of measure IDs if provided in a Parameters object.
Optional parameters include:
practitioner: practitioner for which the measure will be calculated
Currently, measureIdentifier, measureUrl, measure, measureResource and lastReceivedOn parameters are not supported by the test server. The subject-list reportType is not supported by the test server - only subject and population reportTypes are supported at this time,
which will generate individual and summary MeasureReports respectively.
To use, first POST a measure bundle into your database, then send a GET request to http://localhost:3000/4_0_1/Measure/<your-measure-id>/$evaluate (for a single measure) or http://localhost:3000/4_0_1/Measure/$evaluate when specifying measures with the required parameters. Example Parameters object for $evaluate:
{
"resourceType": "Parameters",
"parameter": [
{
"name": "measureId",
"valueString": "BreastCancerScreeningsFHIR"
},
{
"name": "measureId",
"valueString": "CervicalCancerScreeningFHIR"
},
{
"name": "periodEnd",
"valueString": "2022-12-31"
},
{
"name": "periodStart",
"valueString": "2022-01-01"
},
{
"name": "reportType",
"valueString": "population"
}
]
}This operation will execute in a multi-process manner by chunking up the patients to smaller groups and executing across 5 processes if there are more than 100 calculations to execute. The settings for this multi-process "Scaled" calculation can be configured in the .env file:
| ENV Variable | Description | Default Value |
|---|---|---|
EXEC_WORKERS |
Number of worker processes. 0 will disable multi-process calculation. | 5 |
SCALED_EXEC_THRESHOLD |
Calculation count threshold to execute in worker processes. | 100 |
SCALED_EXEC_MAX_JOBSIZE |
Maximum patients to put in each worker job. | 15 |
SCALED_EXEC_STRATEGY |
Patient source strategy to use for scaled calculation (mongo or bundle) |
bundle |
This operation returns a Parameters object with 0..* Bundles, each of which must contain at least one MeasureReport. Each bundle contains MeasureReports associated with exactly one measure. Check out the $evaluate operation spec for more information.
This operation calculates gaps in care for a given patient against the given measure.
Required parameters include:
periodStart: start of the measurement periodperiodEnd: end of the measurement periodstatus: status of the care gap
The user also SHALL include either
subject: subject for which the measure will be calculated ORorganization: Reference to an organization for which the gaps in care report will be created ORorganizationandpractitioner: Reference to a generalPractitioner for which the gaps in care report should be created
The user MAY include
measureIdORmeasureIdentifierORmeasureURL: a measure identification field for which the gaps in care will be reported ORprogram: programs that a provider participates in, for which only associated measures will be used to report gaps in care
Otherwise all available measures will be used.
Currently, topic and using both a measure identification and 'program' at the same time is not yet supported by the test server.
To use, first POST a measure bundle into your database, then send a GET request to http://localhost:3000/4_0_1/Measure/$care-gaps with the required parameters.
Check out the $care-gaps operation spec for more information.
This operation retrieves all the data requirements for a given measure as a FHIR library.
Optional parameters for this function include:
periodStart: start of the measurement periodperiodEnd: end of the measurement period
If either periodStart or periodEnd parameter is supplied without the other, a measurement period will be used with duration 1 year starting or ending at the provided date. If periodStart and periodEnd parameters are omitted entirely, the measurement period for the operation will default to the effectivePeriod of the referenced FHIR Measure. If no effectivePeriod property is present, dateFilters will be excluded from the returned FHIR Library entirely.
To use, first POST a measure bundle into your database, then send a GET request to http://localhost:3000/4_0_1/Measure/<your-measure-id>/$data-requirements.
Check out the $data-requirements operation spec for more information.
This operation takes 1..* bundles. Each transaction bundle should be for a single subject and contain 1..* MeasureReport(s), one for each measure, along with a set of required data with which to calculate the measures. The server adds new documents to the database for each contained FHIR object. To use, send a valid FHIR parameters object in a POST request to http://localhost:3000/4_0_1/Measure/$submit-data.
Check out the deqm $submit-data operation spec for more information.
This operation returns a searchset bundle containing all the information related to a patient. If no patient ID is specified, bundle will contain information for all patients.
To use, first POST a bundle into your database, then send a GET request to http://localhost:3000/4_0_1/Patient/<your-patient-id>/$everything or http://localhost:3000/4_0_1/Patient/$everything.
Check out the Patient-everything operation spec for more information.
The server contains functionality for Bulk Import workflow capabilities as defined by the Draft Bulk Submit IG. This functionality works with a Bulk Export server, see the bulk-export-server repository for an example.
The first step in the $bulk-submit operation workflow is to gather data for submission and retrieve an endpoint from a Bulk Export Server that returns a Bulk Export Manifest with a pre-coordinated FHIR data set. The manifest URL can be obtained with the bulk-export-server $export operation. The export manifest URL can be found at the $export response Content-Location.
To kickoff a bulk submit operation, POST a valid FHIR Parameters resource to http://localhost:3000/4_0_1/$bulk-submit with the following required parameters:
submitter(Identifier): identifier that must match a system and code specified by the Data RecipientsubmissionId(string): ID of the submission, must be unique for thesubmitterfhirBaseUrl(string): base url to be used by the Data Recipient when resolving relative references in the submitted resources
The server supports the following optional parameters:
manifestUrl(string): URL pointing to a Bulk Export Manifest with a pre-coordinated FHIR data set, MAY be omitted when the operation is being called to set the submissionStatus tocompleteoraborted
Example request body for a POST to http://localhost:3000/4_0_1/$bulk-submit:
{
"resourceType": "Parameters",
"parameter": [
{
"name": "manifestUrl",
"valueString": "http://localhost:3001/bulkstatus/d1551f79-6afa-40c4-95a1-e92b3394d415"
},
{
"name": "submitter",
"valueIdentifier": {
"value": "ExampleSubmitterValue"
}
},
{
"name": "submissionId",
"valueString": "Submission2"
},
{
"name": "fhirBaseUrl",
"valueString": "http://localhost:3001"
}
]
}The server supports the $bulk-submit-status endpoint for when a Data Provider wishes to receive updates on the status of a submission after it has kicked off a Bulk Submit operation.
In order to retrieve submission status resources, send a POST request to http://localhost:3000/4_0_1/$bulk-submit-status with a FHIR Parameters resource with the following required parameters:
submitter(Identifier)submissionId(string)
Example request body for a POST to http://localhost:3000/4_0_1/$bulk-submit-status:
{
"resourceType": "Parameters",
"parameter": [
{
"name": "submitter",
"valueIdentifier": {
"value": "ExampleSubmitterValue"
}
},
{
"name": "submissionId",
"valueString": "Submission2"
}
]
}If successful, the operation will respond with a Content-Location header with the absolute URL of an endpoint for subsequent status requests (polling location).
The server follows a FHIR Asynchronous Request Pattern as defined by the Bulk Submit Draft IG for request and response flows following a Bulk Status request.
The server's current implementation returns a partial export manifest and 202 while the submission is incomplete or is being processed. When complete, it returns an export manifest and 200 status.
Copyright 2021-2022 The MITRE Corporation
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.