From c149815e48ba59c82d02f91516878fe238f02c59 Mon Sep 17 00:00:00 2001 From: emmastephenson <80282552+emmastephenson@users.noreply.github.com> Date: Thu, 11 May 2023 10:55:55 -0700 Subject: [PATCH] Update FHIR converter API docs (#521) --- containers/fhir-converter/app/main.py | 73 ++++- .../fhir-converter/assets/sample_request.hl7 | 6 + .../sample_vxu_fhir_conversion_response.json | 273 ++++++++++++++++++ containers/fhir-converter/description.md | 100 ++++--- 4 files changed, 409 insertions(+), 43 deletions(-) create mode 100644 containers/fhir-converter/assets/sample_request.hl7 create mode 100644 containers/fhir-converter/assets/sample_vxu_fhir_conversion_response.json diff --git a/containers/fhir-converter/app/main.py b/containers/fhir-converter/app/main.py index d68e6e118a..8797cef079 100644 --- a/containers/fhir-converter/app/main.py +++ b/containers/fhir-converter/app/main.py @@ -4,10 +4,40 @@ import uuid from enum import Enum from fastapi import FastAPI, Response, status -from pydantic import BaseModel - -# Instantiate FastAPI via PHDI's BaseService class -app = FastAPI() +from pydantic import BaseModel, Field + +# Reading sample request & response files for docs +raw_sample_response = json.load( + open( + Path(__file__).parent.parent + / "assets" + / "sample_vxu_fhir_conversion_response.json" + ) +) +sample_response = {200: raw_sample_response} + +sample_request = open( + Path(__file__).parent.parent / "assets" / "sample_request.hl7" +).read() + +description = (Path(__file__).parent.parent / "description.md").read_text( + encoding="utf-8" +) + +app = FastAPI( + title="PHDI FHIR Converter Service", + version="0.0.1", + contact={ + "name": "CDC Public Health Data Infrastructure", + "url": "https://cdcgov.github.io/phdi-site/", + "email": "dmibuildingblocks@cdc.gov", + }, + license_info={ + "name": "Creative Commons Zero v1.0 Universal", + "url": "https://creativecommons.org/publicdomain/zero/1.0/", + }, + description=description, +) class InputType(str, Enum): @@ -92,18 +122,45 @@ class FhirConverterInput(BaseModel): Input parameters for the FHIR Converter. """ - input_data: str - input_type: InputType - root_template: RootTemplate + input_data: str = Field( + description="The message to be converted as a string.", + example=sample_request, + ) + input_type: InputType = Field( + description="The type of message to be converted.", example="vxu" + ) + root_template: RootTemplate = Field( + description="Name of the liquid template within to be used for conversion.", + example="VXU_V04", + ) @app.get("/") async def health_check(): + """ + Check service status. If an HTTP 200 status code is returned along with + '{"status": "OK"}' then the FHIR conversion service is available and running + properly. + """ return {"status": "OK"} -@app.post("/convert-to-fhir", status_code=200) +@app.post( + "/convert-to-fhir", + status_code=200, + responses=sample_response, +) async def convert(input: FhirConverterInput, response: Response): + """ + Converts an HL7v2 or C-CDA message to FHIR format using the Microsoft FHIR + Converter CLI tool. When conversion is successful, a dictionary containing the + response from the FHIR Converter is returned. + + In order to successfully call this function, the Microsoft FHIR Converter tool + must be installed. For information on how to do this, please refer to the + description.md file. The source code for the converter can be found at + https://github.com/microsoft/FHIR-Converter. + """ result = convert_to_fhir(**dict(input)) if "original_request" in result.get("response"): response.status_code = status.HTTP_400_BAD_REQUEST diff --git a/containers/fhir-converter/assets/sample_request.hl7 b/containers/fhir-converter/assets/sample_request.hl7 new file mode 100644 index 0000000000..0efeb4cece --- /dev/null +++ b/containers/fhir-converter/assets/sample_request.hl7 @@ -0,0 +1,6 @@ +MSH|^~\&|WIR11.3.2^^|WIR^^||WIRPH^^|20200514010000-0400||VXU^V04|2020051411020600|P^|2.4^^|||ER +PID|||3054790^^^^SR^~^^^^PI^||ZTEST^PEDIARIX^^^^^^|HEPB^DTAP^^^^^^|20180808|M||||||||||||||||||||| +PD1|||||||||||02^^^^^|Y||||A +NK1|1||BRO^BROTHER^HL70063^^^^^|^^NEW GLARUS^WI^^^^^^^| +PV1||R|||||||||||||||||| +RXA|0|999|20180809|20180809|08^HepB pediatric^CVX^90744^HepB pediatric^CPT|1.0|||01^^^^^~38193939^WIR immunization id^IMM_ID^^^|||||||||||NA diff --git a/containers/fhir-converter/assets/sample_vxu_fhir_conversion_response.json b/containers/fhir-converter/assets/sample_vxu_fhir_conversion_response.json new file mode 100644 index 0000000000..117157c110 --- /dev/null +++ b/containers/fhir-converter/assets/sample_vxu_fhir_conversion_response.json @@ -0,0 +1,273 @@ +{"description": "Success", + "content": { + "application/json": { + "examples": { + "elr": { + "value": { + "response": { + "Status": "OK", + "FhirResource": { + "resourceType": "Bundle", + "type": "batch", + "timestamp": "2020-05-14T01:00:00-04:00", + "identifier": { + "value": "2020051411020600" + }, + "id": "945561fc-cf00-ebd7-5f1c-865ab4abfcb5", + "entry": [ + { + "fullUrl": "urn:uuid:53d0ea89-a281-523f-f0fb-02e3ee1ef0a2", + "resource": { + "resourceType": "MessageHeader", + "id": "53d0ea89-a281-523f-f0fb-02e3ee1ef0a2", + "source": { + "name": "WIR11.3.2", + "_endpoint": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unknown" + } + ] + } + }, + "destination": [ + { + "_endpoint": { + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/data-absent-reason", + "valueCode": "unknown" + } + ] + }, + "receiver": { + "reference": "Organization/f51a22ef-628f-d014-5a33-da96b68ae53d" + } + } + ], + "meta": { + "tag": [ + { + "code": "P", + "system": "http://terminology.hl7.org/CodeSystem/v2-0103" + } + ] + }, + "eventCoding": { + "code": "V04", + "system": "http://terminology.hl7.org/CodeSystem/v2-0003", + "display": "VXU^V04" + }, + "sender": { + "reference": "Organization/b727354b-9ca6-74fd-6b6b-ae0851c7998a" + } + }, + "request": { + "method": "PUT", + "url": "MessageHeader/53d0ea89-a281-523f-f0fb-02e3ee1ef0a2" + } + }, + { + "fullUrl": "urn:uuid:d24c7a73-ebcf-8f4f-51bc-e95f47452e80", + "resource": { + "resourceType": "Provenance", + "id": "d24c7a73-ebcf-8f4f-51bc-e95f47452e80", + "text": { + "status": "generated", + "div": "

Resource bundle generated on 2023-05-03T19:07:14.523Z using Microsoft FHIR Converter.Template Version: TEMPLATE_VERSION_PLACEHOLDER.Template URL: https://github.com/microsoft/FHIR-Converter/releases/download/vTEMPLATE_VERSION_PLACEHOLDER/Hl7v2DefaultTemplates.tar.gz.Root template: VXU_V04.

" + }, + "occurredDateTime": "2020-05-14T01:00:00-04:00", + "recorded": "2020-05-14T01:00:00-04:00", + "agent": [ + { + "type": { + "coding": [ + { + "code": "author", + "system": "http://terminology.hl7.org/CodeSystem/provenance-participant-type" + } + ] + }, + "who": { + "reference": "Organization/b727354b-9ca6-74fd-6b6b-ae0851c7998a" + } + } + ], + "activity": { + "coding": [ + { + "display": "VXU^V04^" + } + ] + }, + "target": [ + { + "reference": "Bundle/945561fc-cf00-ebd7-5f1c-865ab4abfcb5" + } + ] + }, + "request": { + "method": "PUT", + "url": "Provenance/d24c7a73-ebcf-8f4f-51bc-e95f47452e80" + } + }, + { + "fullUrl": "urn:uuid:b727354b-9ca6-74fd-6b6b-ae0851c7998a", + "resource": { + "resourceType": "Organization", + "id": "b727354b-9ca6-74fd-6b6b-ae0851c7998a", + "identifier": [ + { + "value": "WIR", + "system": "http://example.com/v2-to-fhir-converter/Identifier/WIR" + } + ] + }, + "request": { + "method": "PUT", + "url": "Organization/b727354b-9ca6-74fd-6b6b-ae0851c7998a" + } + }, + { + "fullUrl": "urn:uuid:f51a22ef-628f-d014-5a33-da96b68ae53d", + "resource": { + "resourceType": "Organization", + "id": "f51a22ef-628f-d014-5a33-da96b68ae53d", + "identifier": [ + { + "value": "WIRPH", + "system": "http://example.com/v2-to-fhir-converter/Identifier/WIRPH" + } + ] + }, + "request": { + "method": "PUT", + "url": "Organization/f51a22ef-628f-d014-5a33-da96b68ae53d" + } + }, + { + "fullUrl": "urn:uuid:3f8fc2a0-1d50-42de-bfed-9c01a071c6b6", + "resource": { + "resourceType": "Patient", + "id": "3f8fc2a0-1d50-42de-bfed-9c01a071c6b6", + "identifier": [ + { + "value": "3054790", + "type": { + "coding": [ + { + "code": "SR", + "system": "http://terminology.hl7.org/CodeSystem/v2-0203", + "display": "State registry ID" + } + ] + } + }, + { + "type": { + "coding": [ + { + "code": "PI", + "system": "http://terminology.hl7.org/CodeSystem/v2-0203", + "display": "Patient internal identifier" + } + ] + } + } + ], + "name": [ + { + "family": "ZTEST", + "given": [ + "PEDIARIX" + ] + } + ], + "birthDate": "2018-08-08", + "gender": "male", + "active": true, + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/patient-mothersMaidenName", + "valueString": "HEPB--DTAP" + } + ], + "contact": [ + { + "address": { + "city": "NEW GLARUS", + "state": "WI" + } + } + ] + }, + "request": { + "method": "PUT", + "url": "Patient/3f8fc2a0-1d50-42de-bfed-9c01a071c6b6" + } + }, + { + "fullUrl": "urn:uuid:caeb94a6-281c-4bd0-1dad-4998a2f80c35", + "resource": { + "resourceType": "Encounter", + "id": "caeb94a6-281c-4bd0-1dad-4998a2f80c35", + "class": { + "code": "R", + "display": "Recurring patient", + "system": "http://terminology.hl7.org/CodeSystem/v2-0004" + }, + "status": "in-progress", + "text": { + "status": "generated", + "div": "

Visit Description:

" + }, + "subject": { + "reference": "Patient/3f8fc2a0-1d50-42de-bfed-9c01a071c6b6" + } + }, + "request": { + "method": "PUT", + "url": "Encounter/caeb94a6-281c-4bd0-1dad-4998a2f80c35" + } + }, + { + "fullUrl": "urn:uuid:1b3b6f92-c3c9-7440-d08b-3023cd94c569", + "resource": { + "resourceType": "RelatedPerson", + "id": "1b3b6f92-c3c9-7440-d08b-3023cd94c569", + "relationship": [ + { + "coding": [ + { + "code": "BRO", + "display": "brother", + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode" + } + ] + } + ], + "address": [ + { + "city": "NEW GLARUS", + "state": "WI" + } + ], + "patient": { + "reference": "Patient/3f8fc2a0-1d50-42de-bfed-9c01a071c6b6" + } + }, + "request": { + "method": "PUT", + "url": "RelatedPerson/1b3b6f92-c3c9-7440-d08b-3023cd94c569" + } + } + ] + } + } +} + } + } + } + } +} \ No newline at end of file diff --git a/containers/fhir-converter/description.md b/containers/fhir-converter/description.md index 467443df8d..67a90ce7b8 100644 --- a/containers/fhir-converter/description.md +++ b/containers/fhir-converter/description.md @@ -1,23 +1,15 @@ -# Microsoft FHIR Converter CLI Installation Guide +# Getting started with the PHDI FHIR Conversion Service + +This service relies on Microsoft's FHIR converter to convert messages. + +If you plan to run the service via Docker, you can skip to [Running with Docker](#Running-with-docker-(recommended-for-production)). This container will automatically use the Microsoft FHIR converter without need for additional installation. + +If you plan to run the service locally via Python, you'll need to install both the Microsoft FHIR Converter CLI and run the PHDI FHIR Converter service. Read on for installation instructions for both. + +## Microsoft FHIR Converter CLI Installation Guide This document provides a guide for installing the [Microsoft FHIR Converter](https://github.com/microsoft/FHIR-Converter) as a Command Line Interface (CLI) tool on Windows, MacOS, and Linux systems, as well as a brief introduction to using the converter. -## Running via Docker -To run the FHIR Converter in a Docker container, follow these steps: - - 1. From the `containers/fhir-converter` directory, run: - `docker build -t fhir-converter .` - 1. Start a container by running: - `docker run -p 8080:8080 fhir-converter` - 1. Using curl or a REST client like Postman or Insomnia, make a POST request to http://localhost:8080/convert-to-fhir with a request body. This request should have keys `input_data`, `input_type`, and `root_template`. `input_type` should be either `hl7v2` or `ccda`. `root_template` should be one of the templates provided with the Microsoft FHIR Converter tool, [found here](https://github.com/microsoft/FHIR-Converter/tree/main/data/Templates). `input_data` should be valid data matching the input type and template. For example: - ``` - { - "input_data": "VALID_INPUT_DATA", - "input_type": "hl7v2", - "root_template": "ADT_A01", - } - ``` - -## Using the .NET Framework +### Using the .NET Framework We will use the .NET SDK to build the FHIR Converter from source code. If you have already installed a .NET SDK, skip to [Download and Build the FHIR Converter](#download-and-build-the-fhir-converter), otherwise follow the steps below to install it on your system. To check if a .NET SDK is installed, try running `dotnet --list-sdks`. You should see an output message that lists the .NET SDK version you have installed, as well as where it's located. It should look something like the following, but note that the version number and filepath will differ depending on which operating system you use and when you installed the .NET SDK. @@ -28,21 +20,21 @@ To check if a .NET SDK is installed, try running `dotnet --list-sdks`. You shoul If you see a message like `Command 'dotnet' not found` (MacOS and Linux) or `The term 'dotnet' is not recognized as the name of a cmdlet, function, script file, or operable program` (Windows), then .NET has not been installed. Additionally, if running `dotnet --list-sdks` does not produce any output, then you likely have the .NET runtime installed, but not the SDK. In either event, you should follow the instructions below to install the SDK. -## Install the .NET SDK +### Install the .NET SDK The instructions for installing the .NET SDK will differ depending on whether you're using Windows, MacOS, or Linux. MacOS and Linux users will utilize the command line to install the software, while Windows users should use the installer. Instructions for both approaches are below. -### MacOS and Linux +#### MacOS and Linux -#### Download the .NET Install Script +##### Download the .NET Install Script Run `wget https://dotnet.microsoft.com/download/dotnet/scripts/v1/dotnet-install.sh` to download the .NET installation script from Microsoft. From the directory containing the `dotnet-install.sh` file, run `sh ./dotnet-install.sh` to execute the script and install .NET. By default, this script installs the .NET SDK, which is perfect for our needs. _Note: Bash is required to run the script. If you are using a different shell, such as zsh, it is recommend to switch to using Bash._ -#### Add .NET to the PATH Environment Variable +##### Add .NET to the PATH Environment Variable Finally, permanently add .NET to you `PATH` variable by running `echo 'export PATH="$PATH:$HOME/.dotnet"' >> ~/.bashrc`. -#### Confirm the Installation +##### Confirm the Installation Restart your shell with `exec $SHELL` and then run `dotnet`. If you get a response that looks like what is shown below, then .NET was installed successfully. ```bash @@ -59,17 +51,17 @@ path-to-application: The path to an application .dll file to execute. ``` -### Windows +#### Windows -#### Install the .NET SDK +##### Install the .NET SDK Navigate to [https://dotnet.microsoft.com/en-us/download](https://dotnet.microsoft.com/en-us/download) and click on the "Download .NET SDK x64" button. Note that the label may read slightly differently if you're using a 32-bit operating system. Clicking this button will download a file with a name similar to `dotnet-sdk-6.0.400-win-x64.exe`, but note that the name of your file may differ if a new version of the SDK has been released. **The most important thing is to ensure that the file is for the dotnet-sdk and for Windows.** Open this file and follow the instructions that are presented to you. If you're asked if you should allow this program to make changes to your machine, select yes. Once the installer is finished, you'll be presented with a screen that summarizes what was installed and where it was saved. The default location should be "C:\Program Files\dotnet\". Open File Explorer, navigate to the installation location (C:\Program Files\dotnet), open the "sdk" folder, and confirm that a folder exists with the .NET SDK version as its name. -#### Add .NET to the PATH Environment Variable +##### Add .NET to the PATH Environment Variable Open your Start Menu and type "Environment Variables" into the search bar. Select "Edit environment variables for your account" from the list of options that appear. In the top section labeled "User variables", click the variable called "Path" and then click the "Edit..." button. A new screen will pop up, and you should click the "New" button on the right-hand side. In the text box that is highlighted, enter "C:\Program Files\dotnet" (without the quotes). Hit enter, click "OK" to close the Path screen, and then click "OK" to close the Environment Variables screen. -#### Confirm the Installation +##### Confirm the Installation Open Powershell and run `dotnet`. If you get a response that looks like when is shown below, then .Net was installed successfully. ```bash @@ -86,9 +78,9 @@ path-to-application: The path to an application .dll file to execute. ``` -## Download and Build the FHIR Converter +### Download and Build the FHIR Converter -### Get Microsoft FHIR Converter +#### Get Microsoft FHIR Converter Using whichever command line tool you are comfortable with (Powershell on Windows, or Terminal on Linux and MacOS), download the FHIR Converter source code from Github with the following command. ```bash @@ -98,29 +90,67 @@ git clone https://github.com/microsoft/FHIR-Converter This will install the most recent version of the tool. However, if you'd like to use a specific version, you can use a command like this one that specifically downloads the 5.0.4 release (most recent at the time of writing). `git clone https://github.com/microsoft/FHIR-Converter.git --branch v5.0.4 --single-branch` -### Build the FHIR Converter Tool +#### Build the FHIR Converter Tool Navigate to the directory that was just created with the `git clone` command, which should be a directory named "FHIR-Converter" inside of your current directory, and run `dotnet build`. _Note: If you're using Windows, it's important to perform this action using Powershell instead of a tool like Git Bash. Due to Windows' use of the `\` as its filepath seperator, other terminals can misinterpret the instructions and fail when trying to access directories._ -## Using the FHIR Converter +### Using the Microsoft FHIR Converter Two examples have been provided below of using the FHIR Converter via the `dotnet run` function. Please note that `--` is used to deliminate between arguments that should be passed to `dotnet` as opposed arguments that `dotnet` should be pass to the application, in this case the FHIR Converter, that it is being used to run. Additionaly, the `-p` option is only required when not calling `dotnet run` from the `FHIR-Converter/src/Health.Fhir.Liquid.Converter.Tool/` directory. For additional information on `dotnet run` please refer to [this documentation from Microsoft](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-run). -### Message in File to FHIR +#### Message in File to FHIR The following command can be used to convert a message from a file to FHIR. `dotnet run convert -p path-to-Microsoft.Health.Fhir.Liquid.Converter.Tool/ -- -d path-to-template subdirectory-for-message-type -r root-template -n path-to-file-to-be-converted -f path-to-output` -### Covert Message Content Directory to FHIR +#### Covert Message Content Directory to FHIR The following command can be used to convert the contents of a message provided directly as a string to FHIR. `dotnet run convert -p path-to-Microsoft.Health.Fhir.Liquid.Converter.Tool/ -- -d path-to-template subdirectory-for-message-type -r root-template -c message-content -f path-to-output` _Note: The use of `--` in the command is to separate the command line parameters that are passed to .NET vs those that are passed to the FHIR Converter_ -### Using an Alias +#### Using an Alias To avoid the need for typing `dotnet run convert -p path-to-Microsoft.Health.Fhir.Liquid.Converter.Tool/ -- ` every time you'd like to convert HL7, it is recommended that you create an alias. Instructions for creating an alias on Windows, MacOS, and Linux can be found [here](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/set-alias?view=powershell-7.2), [here](https://wpbeaches.com/make-an-alias-in-bash-or-zsh-shell-in-macos-with-terminal/), and [here](https://www.geeksforgeeks.org/alias-command-in-linux-with-examples/), respectively. -# License + +## Running the PHDI FHIR Conversion Service + +Once the Microsoft FHIR converter is installed, the FHIR conversion service can be run using Docker (or any other OCI container runtime e.g., Podman), or directly from the Python source code. + +### Running with Docker (Recommended for production) + +To run the FHIR conversion service with Docker follow these steps. +1. Confirm that you have Docker installed by running `docker -v`. If you do not see a response similar to what is shown below, follow [these instructions](https://docs.docker.com/get-docker/) to install Docker. +``` +❯ docker -v +Docker version 20.10.21, build baeda1f +``` +2. Download a copy of the Docker image from the PHDI repository by running `docker pull ghcr.io/cdcgov/phdi/fhir-converter:main`. +3. Run the service with ` docker run -p 8080:8080 ghcr.io/cdcgov/phdi/fhir-converter:main`. + +Congratulations, the ingestion service should now be running on `localhost:8080`! + +### Running from Python Source Code +For local development, it may be preferred to run the service directly from Python. To do so, follow the steps below. + +1. Ensure that both Git and Python 3.10 or higher are installed. +2. Clone the PHDI repository with `git clone https://github.com/CDCgov/phdi`. +3. Navigate to `/phdi/containers/fhir-converter/`. +4. Make a fresh virtual environment with `python -m venv .venv`. +5. Activate the virtual environment with `source .venv/bin/activate` (MacOS and Linux), `venv\Scripts\activate` (Windows Command Prompt), or `.venv\Scripts\Activate.ps1` (Windows PowerShell). +5. Install all of the Python dependencies for the ingestion service with `pip install -r requirements.txt` into your virtual environment. +6. Run the FHIR Converter on `localhost:8080` with `python -m uvicorn app.main:app --host 0.0.0.0 --port 8080`. + +### Building the Docker Image + +To build the Docker image for the FHIR conversion service from source code instead of downloading it from the PHDI repository, follow these steps. +1. Ensure that both [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) and [Docker](https://docs.docker.com/get-docker/) are installed. +2. Clone the PHDI repository with `git clone https://github.com/CDCgov/phdi`. +3. Navigate to `/phdi/containers/fhir-converter/`. +4. Run `docker build -t fhir-converter .`. +5. Run the service with `docker run -p 8080:8080 fhir-converter`. + +# License (for Microsoft FHIR Converter) MIT License