From cf84fb92074c6f75cc92e4019543f3d04592c5a1 Mon Sep 17 00:00:00 2001 From: Sean Fong Date: Wed, 10 Jul 2024 13:55:28 +0930 Subject: [PATCH 1/4] Add $convert endpoint --- services/extract-express/package.json | 2 +- services/extract-express/src/debug.ts | 76 +++++++++++++++++ .../src/fhirMappingLanguage.ts | 24 ++++++ services/extract-express/src/index.ts | 83 ++++++++++++++++++- .../extract-express/src/operationOutcome.ts | 28 +++++++ services/extract-express/src/transform.ts | 51 ++++++++++-- 6 files changed, 255 insertions(+), 9 deletions(-) create mode 100644 services/extract-express/src/debug.ts create mode 100644 services/extract-express/src/fhirMappingLanguage.ts diff --git a/services/extract-express/package.json b/services/extract-express/package.json index 17a61ca5..767ee9b1 100644 --- a/services/extract-express/package.json +++ b/services/extract-express/package.json @@ -5,7 +5,7 @@ "main": "lib/index.js", "scripts": { "compile": "tsc", - "start": "node lib/index.js", + "start": "node --inspect lib/index.js", "start:watch": "node --inspect --watch lib/index.js", "test": "echo \"Error: no test specified\" && exit 1" }, diff --git a/services/extract-express/src/debug.ts b/services/extract-express/src/debug.ts new file mode 100644 index 00000000..cdc7979d --- /dev/null +++ b/services/extract-express/src/debug.ts @@ -0,0 +1,76 @@ +/* + * Copyright 2024 Commonwealth Scientific and Industrial Research + * Organisation (CSIRO) ABN 41 687 119 230. + * + * 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.0 + * + * Unless 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. + */ + +import type { OperationOutcome, Parameters, ParametersParameter, StructureMap } from 'fhir/r4b'; + +export function responseIsParametersResource(parameters: any): parameters is DebugOutputParameters { + return ( + parameters && + parameters.resourceType === 'Parameters' && + !!parameters.parameter && + parameters.parameter.length > 0 && + parameters.parameter[2].name === 'parameters' && + parameters.parameter[2].part.length > 0 && + !!parameters.parameter[2].part[1] && + parameters.parameter[2].part[1].name === 'source' && + !!parameters.parameter[2].part[1].resource && + parameters.parameter[2].part[1].resource.resourceType === 'StructureMap' + ); +} + +export function getStructureMapFromDebugOutputParameters( + outputParameters: any +): StructureMap | null { + if (!responseIsParametersResource(outputParameters)) { + return null; + } + + return outputParameters.parameter[2].part[1].resource; +} + +export interface DebugOutputParameters extends Parameters { + parameter: [OutcomeParameter, ResultParameter, DebugParametersParameter, TraceParameter]; +} + +interface OutcomeParameter extends ParametersParameter { + name: 'outcome'; + resource: OperationOutcome; +} + +interface ResultParameter extends ParametersParameter { + name: 'result'; + valueString: string; +} + +interface DebugParametersParameter extends ParametersParameter { + name: 'parameters'; + part: [ + { + name: 'evaluator'; + valueString: string; + }, + { + name: 'source'; + resource: StructureMap; + } + ]; +} + +interface TraceParameter extends ParametersParameter { + name: 'content'; + part: any[]; +} diff --git a/services/extract-express/src/fhirMappingLanguage.ts b/services/extract-express/src/fhirMappingLanguage.ts new file mode 100644 index 00000000..315fc076 --- /dev/null +++ b/services/extract-express/src/fhirMappingLanguage.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2024 Commonwealth Scientific and Industrial Research + * Organisation (CSIRO) ABN 41 687 119 230. + * + * 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.0 + * + * Unless 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. + */ + +export function getFhirMappingLanguageMap(body: any): string | null { + if (typeof body === 'string' && body.includes('map')) { + return body; + } + + return null; +} diff --git a/services/extract-express/src/index.ts b/services/extract-express/src/index.ts index d77ff000..6924c5e0 100644 --- a/services/extract-express/src/index.ts +++ b/services/extract-express/src/index.ts @@ -19,6 +19,8 @@ import express from 'express'; import cors from 'cors'; import { getQuestionnaireResponse } from './questionnaireResponse'; import { + createFailStructureMapConversionOutcome, + createInvalidFhirMappingLanguageMap, createInvalidParametersOutcome, createInvalidQuestionnaireCanonicalOutcome, createNoFormsServerUrlSetOutcome, @@ -29,8 +31,14 @@ import { } from './operationOutcome'; import { getQuestionnaire } from './questionnaire'; import { getTargetStructureMap, getTargetStructureMapCanonical } from './structureMap'; -import { createTransformInputParameters, invokeTransform } from './transform'; +import { + createTransformInputParametersForConvert, + createTransformInputParametersForExtract, + invokeTransform +} from './transform'; import dotenv from 'dotenv'; +import { getFhirMappingLanguageMap } from './fhirMappingLanguage'; +import { getStructureMapFromDebugOutputParameters } from './debug'; const app = express(); const port = 3003; @@ -52,6 +60,7 @@ app.use( // Allows the app to accept JSON and URL encoded data up to 50MB app.use(express.json({ limit: '50mb' })); app.use(express.urlencoded({ extended: true })); +app.use(express.text()); // Allows the app to work behind reverse proxies, forwarding the correct req.protocol to the /StructureMap/$transform call // Without this, doing a HTTPS $extract call will result in a HTTP $transform call @@ -136,7 +145,7 @@ app.post('/fhir/QuestionnaireResponse/\\$extract', async (req, res) => { return; } - const transformInputParameters = createTransformInputParameters( + const transformInputParameters = createTransformInputParametersForExtract( targetStructureMap, questionnaireResponse ); @@ -165,6 +174,76 @@ app.post('/fhir/QuestionnaireResponse/\\$extract', async (req, res) => { } }); +app.get('/fhir/\\$convert', (_, res) => { + res.send( + 'This service is healthy!\nHowever, this server only supports StructureMap/$convert.\nPerform a POST request to /fhir/StructureMap/$convert to convert a FHIR Mapping Language map to a StructureMap resource.' + ); +}); + +app.get('/fhir/StructureMap/\\$convert', (_, res) => { + res.send( + 'This service is healthy!\nPerform a POST request to the same path to convert a FHIR Mapping Language map to a StructureMap resource.' + ); +}); + +app.post('/fhir/StructureMap/\\$convert', async (req, res) => { + let ehrServerUrl = req.protocol + '://' + req.get('host') + '/fhir'; + let ehrServerAuthToken: string | null = null; + + // Set EHR server URL and auth token if provided in env variables + if (EHR_SERVER_URL) { + ehrServerUrl = EHR_SERVER_URL; + ehrServerAuthToken = EHR_SERVER_AUTH_TOKEN ?? null; + } + + try { + // Get FHIR Mapping Language map from the request body + const body = req.body; + const fhirMappingLanguageMap = getFhirMappingLanguageMap(body); + + if (!fhirMappingLanguageMap) { + const outcome = createInvalidFhirMappingLanguageMap(); + res.status(400).json(outcome); + return; + } + + const transformInputParameters = + createTransformInputParametersForConvert(fhirMappingLanguageMap); + + const outputParameters = await invokeTransform( + transformInputParameters, + ehrServerUrl, + ehrServerAuthToken ?? undefined, + true + ); + + // Get StructureMap resource from the output parameters + const structureMap = getStructureMapFromDebugOutputParameters(outputParameters); + if (!structureMap) { + const outcome = createFailStructureMapConversionOutcome(); + res.status(400).json(outcome); + return; + } + + res.json(structureMap); + } catch (error) { + console.error(error); + if (error instanceof Error) { + res.status(500).json(createOperationOutcome(error?.message)); // Sending the error message as an OperationOutcome + return; + } + + // If the error is not an instance of Error, send a generic error message + res + .status(500) + .json( + createOperationOutcome( + 'Something went wrong here. Please raise a GitHub issue at https://github.com/aehrc/smart-forms/issues/new' + ) + ); + } +}); + app.listen(port, () => { console.log(`Transform Express app listening on port ${port}`); }); diff --git a/services/extract-express/src/operationOutcome.ts b/services/extract-express/src/operationOutcome.ts index 5d130370..e58c78a2 100644 --- a/services/extract-express/src/operationOutcome.ts +++ b/services/extract-express/src/operationOutcome.ts @@ -43,6 +43,19 @@ export function createInvalidParametersOutcome(): OperationOutcome { }; } +export function createInvalidFhirMappingLanguageMap(): OperationOutcome { + return { + resourceType: 'OperationOutcome', + issue: [ + { + severity: 'error', + code: 'invalid', + details: { text: 'Input provided is not a valid FHIR Mapping Language map.' } + } + ] + }; +} + export function createInvalidQuestionnaireCanonicalOutcome(): OperationOutcome { return { resourceType: 'OperationOutcome', @@ -109,6 +122,21 @@ export function createNoTargetStructureMapFoundOutcome( }; } +export function createFailStructureMapConversionOutcome(): OperationOutcome { + return { + resourceType: 'OperationOutcome', + issue: [ + { + severity: 'error', + code: 'invalid', + details: { + text: `Failed to convert the provided FHIR Mapping Language map to a StructureMap.` + } + } + ] + }; +} + export function createOperationOutcome(errorMessage: string): OperationOutcome { return { resourceType: 'OperationOutcome', diff --git a/services/extract-express/src/transform.ts b/services/extract-express/src/transform.ts index f9595318..cf6eecf5 100644 --- a/services/extract-express/src/transform.ts +++ b/services/extract-express/src/transform.ts @@ -24,7 +24,7 @@ import type { } from 'fhir/r4b'; import { HEADERS } from './globals'; -export function createTransformInputParameters( +export function createTransformInputParametersForExtract( targetStructureMap: StructureMap, questionnaireResponse: QuestionnaireResponse ): TransformInputParameters { @@ -43,12 +43,41 @@ export function createTransformInputParameters( }; } +export function createTransformInputParametersForConvert( + fhirMappingLanguageMap: string +): TransformInputParameters { + return { + resourceType: 'Parameters', + parameter: [ + { + name: 'source', + valueString: fhirMappingLanguageMap + }, + // Hardcoded content to be empty QuestionnaireResponse since it is not used in the conversion + { + name: 'content', + resource: { + resourceType: 'QuestionnaireResponse', + status: 'in-progress' + } + } + ] + }; +} + export async function invokeTransform( transformInputParameters: TransformInputParameters, ehrServerUrl: string, - ehrServerAuthToken?: string + ehrServerAuthToken?: string, + debugMode?: boolean ): Promise { - const requestUrl = `${ehrServerUrl}/StructureMap/$transform`; + let requestUrl = `${ehrServerUrl}/StructureMap/$transform`; + + // Brian's demo-map-server by default return xml when debug=true, explicitly set it to json + if (debugMode) { + requestUrl += '?debug=true&_format=json'; + } + const headers = ehrServerAuthToken ? { ...HEADERS, Authorization: `Bearer ${ehrServerAuthToken}` } : HEADERS; @@ -59,8 +88,11 @@ export async function invokeTransform( }); if (!response.ok) { + const debugModeMessage = debugMode + ? '\nNote: The input FML map might not be valid. If it is valid but you are still getting this error, please raise a GitHub issue at https://github.com/aehrc/smart-forms/issues/new' + : ''; throw new Error( - `HTTP error when performing ${ehrServerUrl}/StructureMap/$transform. Status: ${response.status}` + `HTTP error when performing ${ehrServerUrl}/StructureMap/$transform. Status: ${response.status}${debugModeMessage}` ); } @@ -68,14 +100,21 @@ export async function invokeTransform( } export interface TransformInputParameters extends Parameters { - parameter: [SourceParameter, ContentParameter]; + parameter: + | [SourceResourceParameter, ContentParameter] + | [SourceValueStringParameter, ContentParameter]; } -interface SourceParameter extends ParametersParameter { +interface SourceResourceParameter extends ParametersParameter { name: 'source'; resource: StructureMap; } +interface SourceValueStringParameter extends ParametersParameter { + name: 'source'; + valueString: string; +} + interface ContentParameter extends ParametersParameter { name: 'content'; resource: FhirResource; From 5343ad04dae7e701e934d3ac070dd61dfa2d5ad5 Mon Sep 17 00:00:00 2001 From: Sean Fong Date: Wed, 10 Jul 2024 14:11:56 +0930 Subject: [PATCH 2/4] Update extract-express and docker push script --- push-extract-image.sh | 2 +- services/extract-express/README.md | 7 +++++-- services/extract-express/package.json | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/push-extract-image.sh b/push-extract-image.sh index 7a0687de..2468377a 100644 --- a/push-extract-image.sh +++ b/push-extract-image.sh @@ -24,5 +24,5 @@ cd services/extract-express && npm run compile && cd - # Build the Docker image for multiple architectures, then push to Docker Hub. docker buildx build --file ./services/extract-express/Dockerfile \ --tag aehrc/smart-forms-extract:latest \ - --tag aehrc/smart-forms-extract:v0.3.1 \ + --tag aehrc/smart-forms-extract:v0.4.0 \ --platform linux/amd64,linux/arm64/v8 --push --no-cache . diff --git a/services/extract-express/README.md b/services/extract-express/README.md index 45452def..07c31f50 100644 --- a/services/extract-express/README.md +++ b/services/extract-express/README.md @@ -5,6 +5,8 @@ It is an abstraction on top of an existing StructureMap [$transform](https://hl7 A proof-of-concept StructureMap $transform is defined on https://proxy.smartforms.io/fhir/StructureMap/$transform, leveraging Brian's .NET mapping engine from https://github.com/brianpos/fhir-net-mappinglanguage/tree/main/demo-map-server. +A `StructureMap/$convert` operation is also defined in the POC implementation to convert a FHIR Mapping Language map to a StructureMap resource, using the same .NET mapping engine. + ## Configuration Create a .env file (or copy from example.env) in the root of the project with the following: ```env @@ -34,6 +36,7 @@ Docker image: https://hub.docker.com/r/aehrc/smart-forms-extract **By default, ```FORMS_SERVER_URL``` is set to https://smartforms.csiro.au/api/fhir in the Docker image.** ## Sample implementation -A sample implementation of this service is available at https://proxy.smartforms.io/fhir/QuestionnaireResponse/$extract. +A sample implementation of the `$extract` service is available at https://proxy.smartforms.io/fhir/QuestionnaireResponse/$extract. +`StructureMap/$convert` is available at https://proxy.smartforms.io/fhir/StructureMap/$convert. -Note: The $extract service on https://smartforms.csiro.au/api/fhir only performs processing - it does not persist any data. +Note: The $extract and $convert service on https://proxy.smartforms.io/fhir only performs processing - it does not persist any data. diff --git a/services/extract-express/package.json b/services/extract-express/package.json index 767ee9b1..d99674b9 100644 --- a/services/extract-express/package.json +++ b/services/extract-express/package.json @@ -1,6 +1,6 @@ { "name": "extract-express", - "version": "0.3.1", + "version": "0.4.0", "description": "", "main": "lib/index.js", "scripts": { From 36a30b6a80826bf92390c4fdc8ef811b112fa7ef Mon Sep 17 00:00:00 2001 From: Sean Fong Date: Wed, 10 Jul 2024 15:35:39 +0930 Subject: [PATCH 3/4] Fix correct AWS deployment route for $convert --- .../ehr-proxy/ehr-proxy-app/lib/ehr-proxy-app-stack.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/deployment/ehr-proxy/ehr-proxy-app/lib/ehr-proxy-app-stack.ts b/deployment/ehr-proxy/ehr-proxy-app/lib/ehr-proxy-app-stack.ts index 655d1fa3..f6d6553b 100644 --- a/deployment/ehr-proxy/ehr-proxy-app/lib/ehr-proxy-app-stack.ts +++ b/deployment/ehr-proxy/ehr-proxy-app/lib/ehr-proxy-app-stack.ts @@ -73,7 +73,12 @@ export class EhrProxyAppStack extends cdk.Stack { listener.addAction('EhrProxyExtractAction', { action: ListenerAction.forward([extractTargetGroup]), priority: 1, - conditions: [ListenerCondition.pathPatterns(['/fhir/QuestionnaireResponse/$extract'])] + conditions: [ + ListenerCondition.pathPatterns([ + '/fhir/QuestionnaireResponse/$extract', + '/fhir/StructureMap/$convert' + ]) + ] }); // Create a target for the transform service From c48bb08a61068eae0b7c9742c6d2266675a5bcaa Mon Sep 17 00:00:00 2001 From: Sean Fong Date: Wed, 10 Jul 2024 16:36:51 +0930 Subject: [PATCH 4/4] Add docs for extract --- documentation/docs/operations/extract.mdx | 196 ++++++++++++++++++++++ services/extract-express/README.md | 2 +- 2 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 documentation/docs/operations/extract.mdx diff --git a/documentation/docs/operations/extract.mdx b/documentation/docs/operations/extract.mdx new file mode 100644 index 00000000..4727bb69 --- /dev/null +++ b/documentation/docs/operations/extract.mdx @@ -0,0 +1,196 @@ +--- +sidebar_position: 4 +--- + +# StructureMap $extract + +This $extract **proof-of-concept** reference implementation is an abstraction on top of an existing StructureMap $transform operation. +We leveraged Brian Postlethwaite's [.NET FHIR Mapping Language engine](https://github.com/brianpos/fhir-net-mappinglanguage/tree/main/demo-map-server) to expose a StructureMap $transform operation on https://proxy.smartforms.io/fhir/StructureMap/$transform. + +:::note + +This reference implementation is a proof-of-concept. It is highly likely that the underlying implementation will change in the future. + +::: + +## Useful links + +#### Services links + +Deployed service: https://proxy.smartforms.io/fhir/QuestionnaireResponse/$extract + +Underlying $transform service: https://proxy.smartforms.io/fhir/StructureMap/$transform + +FHIR Mapping Language to StructureMap $convert service: https://proxy.smartforms.io/fhir/StructureMap/$convert + +#### Specification links + +FHIR $extract operation definition: http://hl7.org/fhir/uv/sdc/OperationDefinition/QuestionnaireResponse-extract + +FHIR $transform operation definition: https://hl7.org/fhir/r4/structuremap-operation-transform.html + +FHIR Mapping Language $convert workflow: https://confluence.hl7.org/pages/viewpage.action?pageId=76158820#UsingtheFHIRMappingLanguage-WebServices + +FHIR StructureMap-based extraction: https://hl7.org/fhir/uv/sdc/extraction.html#structuremap-based-extraction + +#### Source code links + +Github: https://github.com/aehrc/smart-forms/tree/main/services/extract-express + +Dockerhub: https://hub.docker.com/r/aehrc/smart-forms-extract + +## Usage + +Resource(s) can be extracted from a QuestionnaireResponse using a **POST** request to a URL such as: + +```http request +https://proxy.smartforms.io/fhir/QuestionnaireResponse/$extract (type-level) +``` + +#### Parameters + +| Name | Cardinality | Type | Documentation | +| ---------------------- | ----------- | -------- | ------------------------------------------------------------------------------------------------------- | +| questionnaire-response | 1..1 | Resource | The QuestionnaireResponse to extract data from. Used when the operation is invoked at the 'type' level. | + +#### Try it out + +[Run In Postman](https://elements.getpostman.com/redirect?entityId=22885901-2af2cfbb-3a0a-49c6-8404-105ef0751415&entityType=collection) + +## How it works + +The $extract operation is an abstraction on top of an existing StructureMap $transform operation. + +#### The underlying $transform + +A [$transform](https://hl7.org/fhir/r4/structuremap-operation-transform.html) operation requires two input parameters: + +1. `source` - Contains the structure map defining the mapping rules +2. `content` - Contains the data to be transformed (in terms of SDC, this is the QuestionnaireResponse) + +The output of $transform is the transformed data, a FHIR resource. + +Taking this logic, we can use a StructureMap `$transform` operation to perform the extraction of resources from a QuestionnaireResponse. Let's say we want to extract a bundle containing an Observation resource from a QuestionnaireResponse. +We need a StructureMap that maps the data from the QuestionnaireResponse to the Observation resource. Normally we would write this mapping in [FHIR Mapping Language](https://www.hl7.org/fhir/mapping-language.html) and convert it to a StructureMap. + +For more information on using the FHIR Mapping Language, refer to https://confluence.hl7.org/display/FHIR/Using+the+FHIR+Mapping+Language. Brian has a really awesome tool that can help you write and test your mappings at https://fhirpath-lab.com/FhirMapper2. + +Once we have both the `source` StructureMap and the `content` QuestionnaireResponse, our $transform request body should look roughly like this: + +```json +{ + "resourceType": "Parameters", + "parameter": [ + { + "name": "source", + "resource": // - + } + }, + { + "name": "content", + "resource": // - a filled QR from + } + ] +} +``` + +Relevant resources: + +`source`- https://smartforms.csiro.au/api/fhir/StructureMap/extract-bmi + +`content`- http://smartforms.csiro.au/fhir/Questionnaire/CalculatedExpressionBMICalculatorPrepop + +[//]: # 'turn it into a microservice' + +Running the $transform operation will return the transformed data, which in this case is a Bundle resource containing the Observation resource: + +```json +{ + "resourceType": "Bundle", + "id": "", + "type": "transaction", + "entry": [ + { + "request": { + "method": "POST", + "url": "Observation" + }, + "resource": { + "resourceType": "Observation", + "status": "final", + "code": { + "coding": [ + { + "system": "http://snomed.info/sct", + "code": "60621009", + "display": "Body mass index" + } + ] + }, + "subject": { + "reference": "Patient/pat-sf" + }, + "valueQuantity": { + "value": 29.55, + "unit": "kg/m2", + "system": "http://unitsofmeasure.org", + "code": "kg/m2" + } + } + } + ] +} +``` + +#### The $extract operation + +Using the logic above, we can abstract the $transform operation into a $extract operation. The $extract operation requires only one input parameter (or you can just provide the QuestionnaireResponse in the request body): + +`questionnaire-response` - Contains the QuestionnaireResponse to extract data from + +The provided QuestionnaireResponse should fulfill two criteria: + +1. It needs to contain a canonical reference in its `questionnaire` property. + +```json +{ + ... + "questionnaire": "https://smartforms.csiro.au/docs/sdc/population/calculated-expression-1|0.1.0", + ... +} +``` + +2. The referenced Questionnaire should have a [questionnaire-targetStructureMap](http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-targetStructureMap) extension. This extension needs to contain a canonical reference to a StructureMap that maps the data from the QuestionnaireResponse to the desired resource(s). + +```json +{ + ... + "extension": [ + { + "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-targetStructureMap", + "valueCanonical": "https://smartforms.csiro.au/docs/StructureMap/extract-bmi" + } + ], + ... +} +``` + +The $extract POC implementation defines a definitional repository to resolve Questionnaires and StructureMaps - https://smartforms.csiro.au/api/fhir. See https://hub.docker.com/r/aehrc/smart-forms-extract for more information. + +The $extract operation will resolve the referenced Questionnaire + StructureMap, and set the StructureMap as the `source` in the $transform operation. The `content` will be the provided QuestionnaireResponse. + +The underlying $transform operation will be executed, and the transformed data will be returned as the output of the $extract operation. + +## The $convert operation + +Brian's [.NET FHIR Mapping Language engine](https://github.com/brianpos/fhir-net-mappinglanguage/tree/main/demo-map-server) has a handy debug mode that can be activated by adding `debug=true` to the $transform query parameters. +The debug payload contains useful details such as warnings/errors, trace output, the converted StructureMap, and the output resource. + +Conveniently, it also accepts both a FHIR Mapping Language map and a StructureMap resource as the `source` input. +This means we can use it as a $convert operation to convert a FHIR Mapping Language map to a StructureMap resource. + +``` +https://proxy.smartforms.io/fhir/StructureMap/$convert +``` + +It expects the request headers for the `Content-Type` to be `text/plain`. The request body should contain the FHIR Mapping Language map, and the response will contain the converted StructureMap resource. diff --git a/services/extract-express/README.md b/services/extract-express/README.md index 07c31f50..3c7ea5e0 100644 --- a/services/extract-express/README.md +++ b/services/extract-express/README.md @@ -33,7 +33,7 @@ You can use `docker run -p 3003:3003 -e EHR_SERVER_URL=https://proxy.smartforms. Docker image: https://hub.docker.com/r/aehrc/smart-forms-extract -**By default, ```FORMS_SERVER_URL``` is set to https://smartforms.csiro.au/api/fhir in the Docker image.** +**By default, ```FORMS_SERVER_URL``` is set to https://smartforms.csiro.au/api/fhir in the Docker image.** This endpoint is used to resolve referenced FHIR Questionnaires and StructureMaps. ## Sample implementation A sample implementation of the `$extract` service is available at https://proxy.smartforms.io/fhir/QuestionnaireResponse/$extract.