Terminology

Note

Access to a terminology service within openFHIR Engine is not included in the standard license. To check if you have access to it, you can check if you license.json includes “terminology” within “options”. Alternatively, you can do an HTTP GET /terminology/fhir/ConceptMap/123 to verify it.

An important aspect to successful mappings between FHIR and openEHR is a service able to translate codings, enums, terminologies from one to the other.

In many cases, something coded in openEHR is entirely different than what’s coded in FHIR. Similarly and perhaps even more problematic is when something coded in openEHR is of value not allowed in FHIR (i.e. Observation.status, where in FHIR is has fixed pre-defined values).

For this purpose, openFHIR Engine has a built-in terminology service according to https://build.fhir.org/terminology-service.html Implementation Guide. It works with FHIR ConceptMaps to translate from one coding to another.

Simplified inline translations

For simple inline translations (i.e. of enums), alternative to ConceptMap is providing a translation inline within model mappers.

Note

This is outside the scope of standard FHIR Connect specification (.model json schema). Additional properties (terminology section) is an extension to the standard json schema.

Example of an inline terminology mapping:

- name: "status"
  with:
    fhir: "$fhirResource.status"
    openehr: "$openEhrArchetype.advance_care_directive.status"
    type: "TEXT"
  terminology:
    type: "inline"
    mappings:
      - openehr:                      # openEhrFinal value from an openEHR Composition will be translated to "final" when doing a mapping to FHIR
          code: "openEhrFinal"
        fhir:
          code: "final"               # final value from an FHIR Resource will be translated to "openEhrFinal" when doing a mapping to an openEHR Composition
      - openehr:
          code: "openEhrPreliminary"
        fhir:
          code: "preliminary"
      - openehr:
          code: "openEhrActive"
        fhir:
          code: "active"

Terminology service

For more complex translations of Codings, CodeableConcepts, .. embedded (or remote, see: Integrations) terminology service can be used.

Note

This is outside the scope of standard FHIR Connect specification (.model json schema). Additional properties (terminology section) is an extension to the standard json schema.

Example of an terminology mapping:

- name: "type of directive"
  with:
    fhir: "$fhirResource.category.coding"
    openehr: "$openEhrArchetype.advance_care_directive.type_of_directive"
    type: "CODING"
  condition:
    targetRoot: "$fhirResource.category.coding"
    targetAttribute: "system"
    operator: "one of"
    criteria: "[urn:oid:2.16.840.1.113883.2.4.3.11.60.40.4.14.1]"
  terminology:   # can be here within a specific mapping or even above in the header of the model.yml, in which case all CODEABLECONCEPT and CODING will try to be translated
    type: "local"         # local means that the embedded openFHIR terminology service will be used; alternatively, 'remote' is possible, see Integrations
    conceptmap: "http://url-of-the-conceptmap" # ConceptMap.url

RESTful API

Note

Main purpose of the RESTful API of the embedded terminology service is to validate it’s state and how it does the translations. When you want to use this terminology as part of the mappings, you don’t need to use this RESTful API (apart from state configuration). All you need to do is reference ConceptMap from mappings (following the ‘terminology’ section syntax described above).

POST /terminology/fhir/ConceptMap

Create a new ConceptMap that will be available for mappings. Alternative to POSTing it like this is to create it as part of the Bootstrapping, see State configuration

Example request:

POST /terminology/fhir/ConceptMap HTTP/1.1
Content-Type: application/json
Body: <FHIR ConceptMap json>
PUT /terminology/fhir/ConceptMap/(id)

Update an existing ConceptMap.

Example request:

PUT /terminology/fhir/ConceptMap/123 HTTP/1.1
Content-Type: application/json
Body: <FHIR ConceptMap json>
GET /terminology/fhir/ConceptMap/(id)

Read an existing ConceptMap.

Example request:

GET /terminology/fhir/ConceptMap/123 HTTP/1.1
Accept: application/json
GET /terminology/fhir/ConceptMap?url=

Search an existing ConceptMap by ConceptMap.url.

Example request:

GET /terminology/fhir/ConceptMap?url=http123 HTTP/1.1
Accept: application/json
POST /terminology/fhir/ConceptMap/(id)/$translate

Translate coding using a specific ConceptMap

Example request:

POST /terminology/fhir/ConceptMap/123/$translate HTTP/1.1
Content-Type: application/json
Body:
  {
    "resourceType": "Parameters",
    "parameter": [
      {
        "name": "sourceCode",   #can also be sourceCoding or sourceCodeableConcept with the corresponding value type underneath
        "valueCode": "female"
      },
      {
        "name": "system",
        "valueUri": "http://123.com"
      },
      {
        "name": "targetSystem",
        "valueUri": "http://456.com"
      }
    ]
  }
POST /terminology/fhir/ConceptMap/$translate

Translate coding using ConceptMap

Example request:

POST /terminology/fhir/ConceptMap/123/$translate HTTP/1.1
Content-Type: application/json
Body:
  {
    "resourceType": "Parameters",
    "parameter": [
      {
        "name": "sourceCode",   #can also be sourceCoding or sourceCodeableConcept with the corresponding value type underneath
        "valueCode": "female"
      },
      {
        "name": "url",
        "valueUri": "http://123.com"  # ConceptMap.url that should be used
      },
      {
        "name": "system",
        "valueUri": "http://123.com"
      },
      {
        "name": "targetSystem",
        "valueUri": "http://456.com"
      }
    ]
  }

ConceptMap

Example ConceptMap

Note: when element.code is * and element.target.code is *, it means it will only translate systems.

{
  "resourceType": "ConceptMap",
  "url": "http://hl7.org/fhir/ConceptMap/101",
  "group": [
    {
      "source": "OID: 2.16.840.1.113883.2.4.3.11.60.40.2.7.15.1",
      "target": "urn:oid:2.16.840.1.113883.2.4.3.11.60.40.4.14.1",
      "element": [
        {
          "code": "*",
          "target": [
            {
              "code": "*"
            }
          ]
        }
      ]
    },
    {
      "source": "urn:oid:2.16.840.1.113883.2.4.3.11.60.40.4.14.1",
      "target": "OID: 2.16.840.1.113883.2.4.3.11.60.40.2.7.15.1",
      "element": [
        {
          "code": "*",
          "target": [
            {
              "code": "*",
              "equivalence": "equivalent"
            }
          ]
        }
      ]
    },
    {
      "source": "http://snomed.info/sct",
      "target": "http://decor.nictiz.nl/fhir/ValueSet/2.16.840.1.113883.2.4.3.11.60.40.2.2.1.1--20171231000000",
      "element": [
        {
          "code": "*",
          "target": [
            {
              "code": "*",
              "equivalence": "equivalent"
            }
          ]
        }
      ]
    },
    {
      "source": "http://decor.nictiz.nl/fhir/ValueSet/2.16.840.1.113883.2.4.3.11.60.40.2.2.1.1--20171231000000",
      "target": "http://snomed.info/sct",
      "element": [
        {
          "code": "*",
          "target": [
            {
              "code": "*",
              "equivalence": "equivalent"
            }
          ]
        }
      ]
    },
    {
      "source": "http://clinical.vitaly.parsek.com/codeable-concept/questionnaire-question-answer-code-simple",
      "target": "",
      "element": [
        {
          "code": "0",
          "target": [
            {
              "code": "at0005",
              "equivalence": "equivalent"
            }
          ]
        },
        {
          "code": "10",
          "target": [
            {
              "code": "at0006",
              "equivalence": "equivalent"
            }
          ]
        },
        {
          "code": "20",
          "target": [
            {
              "code": "at0007",
              "equivalence": "equivalent"
            }
          ]
        },
        {
          "code": "30",
          "target": [
            {
              "code": "at0008",
              "equivalence": "equivalent"
            }
          ]
        },
        {
          "code": "40",
          "target": [
            {
              "code": "at0009",
              "equivalence": "equivalent"
            }
          ]
        },
        {
          "code": "50",
          "target": [
            {
              "code": "at0010",
              "equivalence": "equivalent"
            }
          ]
        },
        {
          "code": "60",
          "target": [
            {
              "code": "at0011",
              "equivalence": "equivalent"
            }
          ]
        },
        {
          "code": "70",
          "target": [
            {
              "code": "at0012",
              "equivalence": "equivalent"
            }
          ]
        },
        {
          "code": "80",
          "target": [
            {
              "code": "at0013",
              "equivalence": "equivalent"
            }
          ]
        },
        {
          "code": "90",
          "target": [
            {
              "code": "at0014",
              "equivalence": "equivalent"
            }
          ]
        },
        {
          "code": "100",
          "target": [
            {
              "code": "at0015",
              "equivalence": "equivalent"
            }
          ]
        }
      ]
    }
  ]
}