[FHIR Terminology Service](https://www.hl7.org/fhir/R4/terminology-service.html) specification describes a set of operations on [CodeSystem](https://www.hl7.org/fhir/R4/codesystem.html), [ValueSet](https://www.hl7.org/fhir/R4/valueset.html) and [ConceptMap](https://www.hl7.org/fhir/R4/conceptmap.html) resources. Among those operations, the following four operations appear to be the most widely adopted ones: |CodeSystem|ValueSet| |-|-| |[$lookup](https://www.hl7.org/fhir/R4/codesystem-operation-lookup.html)
[$validate-code](https://www.hl7.org/fhir/R4/codesystem-operation-validate-code.html)|[$expand](https://www.hl7.org/fhir/R4/valueset-operation-expand.html)
[$validate-code](https://www.hl7.org/fhir/R4/valueset-operation-validate-code.html)| Developing a partial implementation of the specification has been an effective way to explore the [new FHIR framework](https://docs.intersystems.com/irisforhealth20203/csp/docbook/Doc.View.cls?KEY=HXFHIR_server_intro#HXFHIR_server_arch) introduced in IRIS for Health 2020.1. The [implementation](https://github.com/intersystems-ru/fhir-terminology-service) includes four operations listed above, and supports [read](https://www.hl7.org/fhir/R4/http.html#read) and [search](https://www.hl7.org/fhir/R4/http.html#search) interactions for [CodeSystem](https://www.hl7.org/fhir/R4/codesystem.html) and [ValueSet](https://www.hl7.org/fhir/R4/valueset.html) resources. It's important to note that the implementation uses plain ObjectScript persistent classes as source terminology tables. ### Installation and Testing with a Sample Strategy The following list outlines installation and basic testing steps: 1. Install IRIS for Health 2020.1 or newer. 2. Set up a new namespace using ```System Administration``` > ```Configuration``` > ```System Configuration``` > ```Namespaces``` menu of the Portal, or by running the command ```do ##class(HS.HC.Util.Installer).InstallFoundation("")``` in HSLIB namespace. Then import classes from [src/cls](https://github.com/intersystems-ru/fhir-terminology-service/tree/main/src/cls/) and [samples/cls](https://github.com/intersystems-ru/fhir-terminology-service/tree/main/samples/cls/) folders of [intersystems-ru/fhir-terminology-service](https://github.com/intersystems-ru/fhir-terminology-service) GitHub repository. 3. Create a custom FHIR metadata set based on R4 set with additional search parameters defined in [dummy-search-parameters.json](https://github.com/intersystems-ru/fhir-terminology-service/blob/main/src/fhir-search-parameters/dummy-search-parameters.json). This can be done either by using ```##class(HS.FHIRServer.ConsoleSetup).Setup()``` interactive utility or by running the command: ``` do ##class(HS.FHIRServer.Installer).InstallMetadataSet("", "", "HL7v40", $lb(""), 1) ``` * This step is required in order for ```$expand``` and ```$validate-code``` operations to support HTTP GET requests. * Note that FHIR metadata set files packaged with InterSystems IRIS reside in ```/dev/fhir/fhir-metadata``` directory. 4. Create a new FHIR endpoint based on the new metadata set and on [Sample.iscru.fhir.fts.SimpleStrategy](https://github.com/intersystems-ru/fhir-terminology-service/blob/main/samples/cls/Sample/iscru/fhir/fts/SimpleStrategy.cls) class. Again, this can be achieved either by using the interactive utility or by running the command: ``` do ##class(HS.FHIRServer.Installer).InstallInstance("", "Sample.iscru.fhir.fts.SimpleStrategy", "") ``` 5. Allow unauthenticated access to the new endpoint: use the interactive utility or run the following [commands](https://docs.intersystems.com/irisforhealth20203/csp/docbook/Doc.View.cls?KEY=HXFHIR_server_install#HXFHIR_server_install_program_configure): ``` set strategy = ##class(HS.FHIRServer.API.InteractionsStrategy).GetStrategyForEndpoint("") set config = strategy.GetServiceConfigData() set config.DebugMode = 4 do strategy.SaveServiceConfigData(config) ``` 6. Populate [Sample.iscru.fhir.fts.model.CodeTable](https://github.com/intersystems-ru/fhir-terminology-service/blob/main/samples/cls/Sample/iscru/fhir/fts/model/CodeTable.cls): ``` do ##class(Sample.iscru.fhir.fts.model.CodeTable).Populate(10) ``` 7. Import [fhir-terminology-service.postman_collection.json](https://github.com/intersystems-ru/fhir-terminology-service/blob/main/tests/postman/fhir-terminology-service.postman_collection.json) file into Postman, adjust ```url``` variable defined within the collection, and test the service against ```Sample.iscru.fhir.fts.model.CodeTable``` which is a simple persistent class. ### Supported FHIR Interactions Currently the only supported search parameter for both CodeSystem and ValueSet is ```url```. Both HTTP GET and HTTP POST methods are supported for the four operations listed above. The table below lists some of the possible HTTP GET requests against [Sample.iscru.fhir.fts.model.CodeTable](https://github.com/intersystems-ru/fhir-terminology-service/blob/main/samples/cls/Sample/iscru/fhir/fts/model/CodeTable.cls) class. | URI
(to be prepended with ```http://:```) | Description | |----------------------------------------------------------------------------|---------------------------------------------------------------------------------------| | /metadata | Get endpoint's Capability Statement resource. | | /CodeSystem/Sample.iscru.fhir.fts.model.CodeTable | Read CodeSystem resource corresponding to Sample.iscru.fhir.fts.model.CodeTable class.| | /ValueSet/Sample.iscru.fhir.fts.model.CodeTable | Read ValueSet resource corresponding to Sample.iscru.fhir.fts.model.CodeTable class. | | /CodeSystem?url=urn:CodeSystem:CodeTable | Search CodeSystem resource by url. | | /CodeSystem | Output all avaliable CodeSystem resources. | | /ValueSet?url=urn:ValueSet:CodeTable | Search ValueSet resource by url. | | /ValueSet | Output all avaliable ValueSet resources. | | /CodeSystem/$lookup?system=urn:CodeSystem:CodeTable&code=TEST | Given system and code, get all the details about the concept. | | /ValueSet/$expand?url=urn:ValueSet:CodeTable | Expand the ValueSet. | | /CodeSystem/Sample.iscru.fhir.fts.model.CodeTable/$validate-code?code=TEST | Validate that a code is in the code system. | ### Creating a Custom Strategy In order to expose your own persistent classes as FHIR code systems/value sets, you would need to create your custom strategy class by subclassing [iscru.fhir.fts.FTSStrategy](https://github.com/intersystems-ru/fhir-terminology-service/blob/main/src/cls/iscru/fhir/fts/FTSStrategy.cls), and then create FHIR endpoint based on the new custom strategy (see above installation step #4). One class parameter and at least three methods must be overridden by your strategy class: * ```StrategyKey``` class parameter should be assigned some unique value. Name of the current class seems to be a good option. * ```getCodeTablePackage()``` class method should return package name for a given code system (or value set) identified by its [canonical URL](https://www.hl7.org/fhir/R4/resource.html#canonical). Typically all terminology classes belong to one package, so this method would usually return one and the same package name regardless of argument values. * ```getCodePropertyName()``` and ```getDisplayPropertyName()``` class methods should return names of class properties that correspond to ```code``` and ```display``` concept elements. Different classes may have different properties mapped to terminology code/display elements. Other methods and parameters of [iscru.fhir.fts.FTSStrategy](https://github.com/intersystems-ru/fhir-terminology-service/blob/main/src/cls/iscru/fhir/fts/FTSStrategy.cls) that you might find appropriate to override are as follows: * ```listCodeTableClasses()``` class method needs to be overridden in order to support search requests that result in returning all available code systems (or value sets). This method is supposed to return a list of class names of all available terminology classes. [Sample.iscru.fhir.fts.SimpleStrategy](https://github.com/intersystems-ru/fhir-terminology-service/blob/main/samples/cls/Sample/iscru/fhir/fts/SimpleStrategy.cls) contains the following basic implementation of this method: ``` /// Returns a list of all available code table classes. ClassMethod listCodeTableClasses() As %List { #dim sql As %String = "SELECT name FROM %Dictionary.ClassDefinition WHERE name LIKE '" _ ..#codeTablePACKAGE _ ".%' ORDER BY name" #dim resultSet As %SQL.StatementResult = ##class(%SQL.Statement).%ExecDirect(, sql) if (resultSet.%SQLCODE '= 0) && (resultSet.%SQLCODE '= 100) $$$ThrowStatus($$$ERROR($$$SQLError, resultSet.%SQLCODE, resultSet.%Message)) #dim return As %List = "" while resultSet.%Next() { set return = return _ $lb(resultSet.name) } quit return } ``` * ```isExcludedProperty()``` class method has to be overridden if any particular properties of your persistent classes should not show up in CodeSystem resources. By default, this method filters ```Collection```, ```Identity```, ```Internal```, ```MultiDimensional``` and ```Private``` properties out. Note that object reference and stream properties are currently not supported and ignored by the framework. * ```codeSystemUrlPREFIX``` and ```valueSetUrlPREFIX``` class parameters and ```getCodeSystemForClassname()```, ```getValueSetForClassname()```, ```determineCodeTableClassname()``` and ```determineCodeSystemForValueSet()``` methods control how class names are mapped to [canonical URLs](https://www.hl7.org/fhir/R4/resource.html#canonical) and vice versa. By default, the following naming scheme is used for canonical URLs: |CodeSystem|ValueSet| |-|-| |```urn:CodeSystem:```|```urn:ValueSet:```| Note that [logical id](https://www.hl7.org/fhir/R4/resource.html#id) (aka server id) of a CodeSystem/ValueSet resource equals full name of its corresponding class. ### TO DO Currently lacking is support for versioning of code systems, concept hierarchies and ```$subsumes``` operation, ConceptMap resource and plenty of other stuff. Ideas and pull requests are very welcome!