--- type: "doc" source: "source/terminology-service.html" --- \[%settitle Terminology Service%\] \[%file newheader%\] \[%file newnavbar%\] <%txheader service%> ## Terminology Service | Responsible Owner: [\[%wgt vocab%\]]([%wg vocab%]) Work Group | [Standards Status](versions#std-process):[Normative](versions#std-process) | | --- | --- | This specification includes support for the provision of a terminology service - that is, a service that lets healthcare applications make use of codes and value sets without having to become experts in the fine details of code system, value set and concept map resources, and the underlying code systems and terminological principles. ### Conformance A server that supports the mandatory functionality described in the following subsections can be described as a "FHIR Terminology Service". #### RESTful API A FHIR terminology service SHALL support: - the [XML](xml) and [JSON](json) FHIR formats. - the [READ](http#read) and [SEARCH](http#search) interactions for `CodeSystem`, `ValueSet` and `ConceptMap` - the following elements as search parameters for `CodeSystem`, `ValueSet` and `ConceptMap` - `url` - `version` - `name` - `title` - `status` - the [capabilities interaction](http#capabilities) with an absent `mode` parameter or a `mode` parameter with a value of `full` returning a [CapabilityStatement](capabilitystatement) resource which includes the following elements (plus the other requirements for a conformant CapabilityStatement resource instance): - `url` - `version` - `name` - `title` - `status` - `date` - `description` - `kind` with a fixed value of `instance` - `fhirVersion` - the [capabilities interaction](http#capabilities) with a `mode` parameter with a value of `terminology` returning a [TerminologyCapabilities](terminologycapabilities) resource which includes the following elements: - `url` - `name` - `title` - `status` - `date` - `kind` with a fixed value of `instance` - A `codeSystem` data element containing each of the following sub elements for each code system supported for terminology services: - `codeSystem.uri` - `codeSystem.version` (for code systems with a version) - `codeSystem.version.code` (for each version) - `codeSystem.content` #### Terminology Service Operations A FHIR Terminology Service SHALL support the following operations with the associated level and required input parameters: | **Operation** | **System Level** | **Type Level** | **Instance Level** | **Required input parameters** | | --- | --- | --- | --- | --- | | [CodeSystem-lookup](codesystem-operation-lookup) | N/A | Yes | No | - `code` - `system` - `version` | | [CodeSystem-validate-code](codesystem-operation-validate-code) | N/A | Yes | No | - `code` - `system` - `version` - `display` | | [CodeSystem-subsumes](codesystem-operation-subsumes) | N/A | Yes | No | - `codeA` - `codeB` - `system` - `version` | | [ValueSet-expand](valueset-operation-expand) | N/A | Yes | Yes | - `url` - `filter` - `offset` - `count` | | [ValueSet-validate-code](valueset-operation-validate-code) | N/A | Yes | Yes | - `url` - `code` - `system` - `systemVersion` - `display` | | [ConceptMap-translate](conceptmap-operation-translate) | N/A | Yes | Yes | - `url` - `sourceCode` - `system` - `targetCode` - `targetSystem` | \[%impl-note%\] Implementers may choose to follow and optionally implement the additional operations being developed as part of the HL7 Terminology Infrastructure Work Group FHIR Implementation Guide. \[%end-note%\] #### CapabilityStatement and TerminologyCapabilities examples - [FHIR Terminology Service Capability Statement](capabilitystatement-terminology-server) - [FHIR Terminology Service Terminology Capabilities](terminologycapabilities-terminology-server). Note that in this example the code systems referenced in TerminologyCapabilities.codeSystem data elements are examples and support for these should not be considered a mandatory requirement for a FHIR Terminology Service. ### Security Generally, SSL SHOULD be used for all production health care data exchange. Even though terminology servers do not generally handle patient information directly, observers may still be able to infer information about patients by observing the codes and concepts used in terminology service operations, so encryption is still recommended. A terminology server may choose not to authenticate the clients/users in any fashion, but might need to do so in order to limit or account for usage, or enforce agreement to licensing terms. For a value set maintenance server that allows terminologies to be edited, some form of [authorization and/or authentication would be appropriate](security). This specification does not require any particular approach to security. ### Basic Concepts A FHIR terminology service is simply a set of functions built on the definitions provided by a collection of [CodeSystem](codesystem), [ValueSet](valueset) and [ConceptMap](conceptmap) resources, with additional inherently known terminologies providing support. The terminology service builds on the basic principles for using terminologies in FHIR. Implementers should be familiar with: - [Using codes in FHIR](terminologies) - The [CodeSystem](codesystem) resource - The [ValueSet](valueset) resource - The [ConceptMap](conceptmap) resource In addition, implementers should be familiar with the [operations framework](operations). Further useful information about terminologies may be found in: - Underlying Principles: [HL7 v3 Core Principles](http://www.hl7.org/documentcenter/public/standards/V3/core_principles/infrastructure/coreprinciples/v3modelcoreprinciples.html) - SNOMED CT [technical documentation](http://ihtsdo.org/fileadmin/user_upload/doc/). Note: "namespace" is used differently here from the way it is used by IHTSDO (see [discussion here](terminologies)) #### External Code Systems In order to be used with a value set, code systems and their content must be defined somewhere. They can be defined explicitly using the [code system resource](codesystem), or they can be defined elsewhere, and then used in a value set by referencing the correct system url. HL7 Terminology defines a [set of technical identifiers](https://terminology.hl7.org/external_terminologies_csti.html) for commonly encountered code systems, and defines how some work with FHIR (e.g. [SNOMED CT](https://terminology.hl7.org/SNOMEDCT.html), [LOINC](https://terminology.hl7.org/LOINC.html), and [RxNorm](https://terminology.hl7.org/RxNorm.html)). These code systems are often large and have many internally defined properties that are part of their formal definitions. The CodeSystem resource is not an appropriate way to distribute the contents of these code systems; the standard FHIR code system resource simply represents the properties of the code system. Instead, these terminologies provide their own distribution formats, and it is assumed that the content of these code systems are externally known to the terminology server. Most useful terminology servers will make one or more of these external code systems available for use within the value sets that they manage. The list of additional terminologies that a terminology server supports beyond those defined in its value sets is published to clients by referencing code system resources in the server's [Capability Statement](capabilitystatement). { "resourceType" : "CapabilityStatement", "extension" : \[ { "url" : "http://hl7.org/fhir/StructureDefinition/capabilitystatement-supported-system", "valueUri" : "http://loinc.org" }\] } This extension is added to the root [Capability Statement](capabilitystatement). #### Implementation Note When a terminology server exposes an external code system, it makes a set of services available internally that serve the operational interfaces below (starting in [Value Set Expansion](#expand)). The internal server depends on the following logical information for a terminology: - its URL (namespace, and how versioning works) - what codes are valid - what properties can be used to select codes - what implicit value sets exist HL7 Terminology defines these things for common terminologies (including [SNOMED CT](https://terminology.hl7.org/SNOMEDCT.html), [LOINC](https://terminology.hl7.org/LOINC.html), and [RxNorm](https://terminology.hl7.org/RxNorm.html)), and the FHIR specification itself provides the [CodeSystem](codesystem) infrastructure for supporting typical relatively simple small code systems. \[%impl-note%\] _Implementers interested in working with existing published terminologies for which the CodeSystem infrastructure is not suitable should discuss their needs with HL7 to get the list above extended._ \[%end-note%\] Note: A terminology service may choose to expose additional external code system specific related functionality such as summation, or structured search, but these services are outside the scope of the FHIR terminology service. #### Terminology Maintenance The terminology service uses the code systems and value set resources defined on the system - both the implicit ones associated with the external code systems and those explicitly available at the /CodeSystem and /ValueSet endpoints - to serve the operational interface defined below (starting in [Value Set Expansion](#expand)). As code systems and value sets are created, updated or deleted, the outcomes of the operational services change. A terminology server should validate incoming resources and ensure integrity of the terminology services. Typically, servers provide a test and production environment, but there is no explicit notion of this in the interface itself. ### Value Set Expansion A value set describes a set of rules for what codes or concepts are considered to be in the value set. These rules might be simple (e.g., a direct list of codes from a specified version of a code system), or they might be quite complex (e.g., all codes with a particular property from an unspecified version of a code system). A FHIR-enabled application can simply ask a terminology server to figure out all the details and return a list of the current codes in the value set. This is known as ["expanding" the valueset](valueset-operation-expand). As a summary, the client passes the server the following information: - the value set (either by its URL on the RESTful interface, by its logical identifier [(ValueSet.url)](valueset-definitions#ValueSet.url), or directly as a parameter to the call) - (Optionally) a text filter to use to restrict the codes that are returned (e.g., user input text). It is left to server discretion to choose how to apply the text filter - (Optionally) a date at which the expansion should be evaluated (usually, this is the current date/time, but there are circumstances where that is not appropriate) - (Optionally) which page to retrieve - asking the server to break the expansion into a set of chunks - (Optionally) other parameters that supply additional information about how to perform the expansion The server returns a value set that contains the current list of codes that meet the filter criteria (or an [OperationOutcome](operationoutcome) with an error if the expansion fails). Note that some value sets expand to many thousands of codes, or even an infinite number, and for these, the server SHOULD return an [error code _too-costly_](valueset-issue-type#too-costly). In these cases, the client can try again with a more specific text filter to reduce the number of codes returned - this may result in a valid expansion. For further information, consult the [definition of the operation](valueset-operation-expand). The [$expand](valueset-operation-expand) operation has support for paging - for a client to retrieve a big expansion in a set of partial views, in order to present the most optimal user experience. The client specifies both an offset and a count - how many codes per page, and where in the sequence to start. The return expansion specifies the number of concepts in the expansion, and the offset at which this partial view starts. Note that all expansions SHOULD include the total code count, but the offset element SHALL only exist when paging is being used. Expansions that are hierarchical trees of concepts are not subject to paging and the server simply returns the entire expansion. Some example uses for the expansion operation: - get a list of codes to display in a User interface (e.g., a drop-down interface) - a variation on this is to offer the user a text box to type in. As the user types, call the expand operation to provide the user with a list of matching codes/concepts (like a browser search) - fetch a list of codes to use when generating software programming instructions - get a list of codes so that software can check whether a code is valid or not in a specific context **Examples** Expanding a value set that is already registered on the server as "23", with a text filter of "abdo": GET \[base\]/ValueSet/23/$expand?filter=abdo Expanding a value set that is specified by the client (using JSON): POST \[base\]/ValueSet/$expand \[other headers\] { "resourceType" : "Parameters", "parameter" : \[ { "name" : "valueSet", "resource" : { "resourceType" : "ValueSet", \[value set details\] } } \] } The server responds with a value set (this example in XML): HTTP/1.1 200 OK \[other headers\] ### Concept Lookup / Decomposition A system can ask a terminology server to return a set of information about a particular system/code combination using [the lookup operation](codesystem-operation-lookup). The server returns information for both display and processing purposes. The client passes the server the following information: - the code value (either a code, or a Coding datatype) - (Optionally) the id or the url of the code system in which the code is being checked - (Optionally) a date at which the code information should be returned (usually, this is the current date/time, but there are circumstances where that is not appropriate) - (Optionally) a set of properties to return about the code The server returns some or all of the following information: - a human description of the system - a recommended display for the code - properties of the code (e.g., status) - other designations for the code (a value, optionally with language and/or a use code) - relationships between this code and other codes (parent/child properties, etc.) - Component properties of the specified code (e.g., to support reasoning) (e.g., decomposition) The recommended display for the code is a text representation of the code that the terminology server recommends as the default choice to show to the user, though a client may choose out of the other designations if it has reason to. If the client does not ask for any particular properties to be returned, it is at the discretion of the server to decide which properties to return (though note that the "version" property is always returned if the code system has a version). **Examples** Looking up a code in a code system: GET \[base\]/CodeSystem/loinc/$lookup?code=1963-8 Note that the logical id "loinc" is not a reliable identifier across systems; each server assigns logical ids to code system resources however it sees fit. A more reliable query is this: GET \[base\]/CodeSystem/$lookup?system=http://loinc.org&code=1963-8&property=code&property=display&property=designations Lookup the code system using a Coding (this example in XML): POST \[base\]/CodeSystem/$lookup \[other headers\] The server responds with a set of information (JSON this time): HTTP/1.1 200 OK \[other headers\] { "resourceType" : "Parameters", "parameter" : \[ { "name" : "name", "valueString" : "LOINC" }, { "name" : "version", "valueString" : "2.56" }, { "name" : "display", "valueString" : "Bicarbonate \[Moles/volume\] in Serum or Plasma" }, { "name" : "abstract", "valueString" : "false" } \] } #### Standard $lookup Properties The following property names are defined in response to the $lookup operation from all code systems: | **Name** | **Usage** | **Source** | | --- | --- | --- | | name | The name of the code system | system | | version | The version of the code system used for the look up operation | system | | display | The recommended display for the concept, if one is known | designation | | designation | Other designations for the concept | designation | | lang.X | Designations in language X (where X is an IETF Language code, see [BCP-47)](https://www.rfc-editor.org/rfc/rfc5646.html) | designation | In addition, any property codes defined by [this specification](codesystem#defined-props) or by the CodeSystem ([CodeSystem.property.code](codesystem-definitions#CodeSystem.property)) can be returned (and see the definitions for [SNOMED CT](https://terminology.hl7.org/SNOMEDCT.html), [LOINC](https://terminology.hl7.org/LOINC.html), and [RxNorm](https://terminology.hl7.org/RxNorm.html) in HL7 Terminology). ### Value Set Validation One way to determine whether a code is in a value set is to expand the value set (as described above), and then look at the returned codes to see if the code is in the expansion. However, this is not an efficient way to test whether a code is valid, and for some value sets (e.g., with infinite number of members), it cannot work. Instead, a FHIR terminology server provides [a "validate-code" operation](valueset-operation-validate-code). The client passes the server the following information: - the value set (either by its URL on the RESTful interface, by its logical identifier [(ValueSet.url)](valueset-definitions#ValueSet.url), or directly as a parameter to the call) - the code value (either a code + system, a Coding datatype, or a CodeableConcept) - (Optionally) a date at which the expansion should be evaluated (usually, and by default, this is the current date/time, but there are circumstances where that is not appropriate) The server returns a true/false indicating whether the code/concept is valid, and a list of errors and warnings associated with it. The server should also return an appropriate display for the concept for use in a UI context. Note that if the server is passed a CodeableConcept, the server is able to check whether any of the codes are valid against the value set, and also check whether multiple codings are allowed and/or the codings provided are consistent with each other. Every code system has an implicit value set that is "all the concepts defined in the code system" (CodeSystem.valueSet). For some code systems, these value set URIs are defined in advance (e.g., for [LOINC](http://loinc.org), it is `http://loinc.org/vs`). However, for some code systems, they are not known. Clients can refer to these implicit value sets by providing the URI for the code system itself. **Examples** Simple validation of a code/system against a known value set: GET \[base\]/ValueSet/23/$validate-code?system=http://loinc.org&code=1963-8&display=test Validate a CodeableConcept against a client specified value set (this example in JSON): POST \[base\]/ValueSet/$validate-code \[other headers\] { "ResourceType" : "Parameters", "parameter" : \[ { "name" : "coding", "valueCodeableConcept" : { "coding" : { "system" : "http://loinc.org", "code" : "1963-8", "display" : "test" } } }, { "name" : "valueSet", "resource": { "resourceType" : "ValueSet", \[etc.\] } } \] } The server responds with validation information (JSON this time): HTTP/1.1 200 OK \[other headers\] { "resourceType" : "Parameters", "parameter" : \[ { "name" : "result", "valueBoolean" : false }, { "name" : "message", "valueString" : "The display \\"test\\" is incorrect" }, { "name" : "display", "valueString" : "Bicarbonate \[Moles/volume\] in Serum or Plasma" } \] } ### Subsumption testing To test the subsumption relationship between _code/Coding A_ and _code/Coding B_, perform a $subsumes operation. Subsumption testing is based on [the CodeSystem definition of subsumption](codesystem#subsumption). The client passes the server the following information: - the system that identifies the code system in which subsumption testing is to be performed (either by invoking the operation on the code system directly, or referring to it by its canonical URL) - Concepts A and B - either as codes, or Codings - (Optionally) the version of the code system to use (mostly, this should not matter) If the client passes Codings, it is allowed to use code system values that are different from the code system in which subsumption testing is to be performed. In this case, the server SHALL return an error unless the relationships between the various code systems is well defined. If the concepts can be compared, then the server returns an outcome code: | equivalent | Concepts A and B are equivalent | | --- | --- | | subsumes | Concept A subsumes Concept B | | subsumed-by | Concept A is subsumed by Concept B | | not-subsumed | Concepts A and B are not related by any subsumption relationship | **Examples** Test whether a SNOMED CT Concept 'Disorder of liver' (235856003) subsumes 'Viral hepatitis' (3738000): GET \[base\]/CodeSystem/$subsumes?system=http://snomed.info/sct&codeA=235856003&codeB=3738000 Or using Codings: POST \[base\]/CodeSystem/$subsumes \[other headers\] Server response: HTTP/1.1 200 OK \[other headers\] { "resourceType" : "Parameters", "parameter" : \[ { "name" : "outcome", "valueCode" : "subsumes" }, \] } ### Batch Validation It is also possible to validate a set of concepts against their relevant value sets by using the `$validate-code` operation in a [Batch](http#batch) interaction. **Example** A request to validate 2 concepts from a [CDA](http://www.hl7.org/implement/standards/product_brief.cfm?product_id=7) document, with OIDs for value set identifiers: POST \[base\] \[other headers\] { "ResourceType": "Bundle", "type": "batch", "entry": \[{ "request": { "method": "Get", "url": "ValueSet/$validate-code?system=http://loinc.org&code=2324-4&uri=urn:oid:1.2.3.4.6" } }, { "request": { "method": "GET", "url": "ValueSet/$validate-code?system=http://snomed.info/sct&codes=22298006&uri=urn:oid:1.2.3.4.7" } }\] } The server responds with a series of validation outcomes (JSON this time): HTTP/1.1 200 OK \[other headers\] { "ResourceType": "Bundle", "type": "batch-response", "entry": \[{ "resource": { "resourceType": "Parameters", "parameter": \[{ "name": "result", "valueBoolean": false }, { "name": "message", "valueString": "'2324-4' is not a valid LOINC code" }\] } }, { "resource": { "resourceType": "Parameters", "parameter": \[{ "name": "result", "valueBoolean": false }, { "name": "message", "valueString": "The concept is not in the specified value set (\\"Organisms\\")" }, { "name": "display", "valueString": "Myocardial infarction" }\] }\] } ### Translations A client can ask a server to translate a concept from one value set to another. Typically, this is used to translate between code systems (e.g., from LOINC to SNOMED CT, or from a [HL7 V3](https://www.hl7.org/implement/standards/product_brief.cfm?product_id=186) code to a [HL7 V2](http://www.hl7.org/implement/standards/product_brief.cfm?product_id=185) code). The client calls [the translate operation](conceptmap-operation-translate) and passes the following parameters: - a code + system, Coding, or CodeableConcept - a Concept Map to use for the translation - the value set for the context of the source - the value set for the destination The client passes either a concept map, or the value sets for the source and destination context. If there is no concept map, then the server may determine the appropriate map to use from context provided in the value sets. If there is no particular context, the appropriate value sets would be the value sets for the entire coding system at question (e.g., from http://snomed.info/sct to http://loinc.org/vs). The server performs the translation as it is able based on the concept maps that it knows about. If no single mapping can be determined, then the server returns an error. Some servers may require a concept map to use for the translation. **Example** Translate from FHIR Composition status to [HL7 v3](https://www.hl7.org/implement/standards/product_brief.cfm?product_id=186) Act Status (based on [this defined concept map](cm-composition-status-v3)): GET \[base\]/ConceptMap/$translate?system=http://hl7.org/fhir/composition-status &code=preliminary&source=http://hl7.org/fhir/ValueSet/composition-status &target=http://terminology.hl7.org/ValueSet/v3-ActStatus The server responds with validation information: HTTP/1.1 200 OK \[other headers\] { "resourceType" : "Parameters", "parameter" : \[ { "name" : "result", "valueBoolean" : true }, { "name" : "outcome", "valueCoding" : { "system" : "http://terminology.hl7.org/CodeSystem/v3-ActStatus", "code" : "active", } } \] } ### Batch Translation It is also possible to translate a set of concepts against their relevant value sets by using the `$translate` operation in a [Batch](http#batch) interaction. **Example** A request to translate 2 concepts from a [CDA](http://www.hl7.org/implement/standards/product_brief.cfm?product_id=7) document, with OIDs for value set identifiers: POST \[base\] \[other headers\] { "ResourceType": "Bundle", "type": "batch", "entry": \[{ "resource": { "ResourceType": "Parameters", "parameter": \[{ "name": "concept", "valueCodeableConcept": { "system": "http://loinc.org", "code": "2324-4" } }, { "name": "target", "valueUri": "urn:oid:1.2.3.4.6" }\] }, "request": { "method": "POST", "url": "ConceptMap/$translate" } }, { "resource": { "ResourceType": "Parameters", "parameter": \[{ "name": "concept", "valueCodeableConcept": { "system": "http://snomed.info/sct", "code": "22298006" } }, { "name": "target", "valueUri": "urn:oid:1.2.3.4.7" }\] }, { "request": { "method": "POST", "url": "ConceptMap/$translate" } }\] } The server responds with a series of translation outcomes: HTTP/1.1 200 OK \[other headers\] { "ResourceType": "Bundle", "type": "batch-response", "entry": \[{ "resource": { "resourceType": "Parameters", "parameter": \[{ "name": "result", "valueBoolean": false }, { "name": "message", "valueString": "'2324-4' is not a valid LOINC code" }\] } }, { "resource": { "resourceType": "Parameters", "parameter": \[{ "name": "result", "valueBoolean": true }, { "name": "outcome", "valueCodeableConcept": { "coding": { "system": "http://example.com/codesystems/example", "code": "xxxx" } } }\] } }\] } \[%file newfooter%\]