# How to set external terminology validation
**Category:** [Platform](https://discourse.openehr.org/c/platform-implem/7)
**Created:** 2023-03-28 09:24 UTC
**Views:** 1021
**Replies:** 40
**URL:** https://discourse.openehr.org/t/how-to-set-external-terminology-validation/3755
---
## Post #1 by @Alex_Paris
I'm trying to use external terminology validation, right now there is no validation as I'm able to set any value. The default configuration ( [8. Terminology Validation — EHRbase documentation](https://ehrbase.readthedocs.io/en/latest/08_terminology_validation/index.html#configuration)) the validation.external-terminology.enabled=false by default in the application.yml, how can I set that value to true to have external terminology validation?
---
## Post #2 by @ian.mcnicoll
You can set additional properties via the `.env.ehrbase` file, including with a Docker instance - you will need to restart the container though.
The .env files require a particular format to be passed through to Spring.
Probably `VALIDATION_EXTERNAL_TERMINOLOGY_ENABLED = true`
---
## Post #3 by @Alex_Paris
Hi Ian,
is it possible to set that variable having the docker deployed?
---
## Post #4 by @ian.mcnicoll
https://stackoverflow.com/questions/42149529/how-to-reload-environment-variables-in-docker-compose-container-with-minimum-dow
---
## Post #5 by @Alex_Paris
Thanks Ian, I have fixed it!
Now when I'm trying to set a coded text of the external terminology I don't know why all codes are rejected as if they were not in the ValueSet. I follow the documentation and I'm setting the values:
DvCodedText codedText = new DvCodedText();
CodePhrase codePhrase = new CodePhrase();
codePhrase.setTerminologyId(new TerminologyId("http://hl7.org/fhir/ValueSet/condition-code"));
codePhrase.setCodeString("4637005");
codedText.setDefiningCode(codePhrase);
codedText.setValue("Intrahepatic cholestasis");
And the creation of the composition is in the same format as appears in the documentation.
---
## Post #6 by @ian.mcnicoll
The terminologyID should just be the FHIT system value for Snomed CT
codePhrase.setTerminologyId(new TerminologyId("http://snomed.info/sct")
---
## Post #7 by @Alex_Paris
I have tried, with this Value Set of FHIR
codePhrase.setTerminologyId(new TerminologyId("[http://hl7.org/fhir/ValueSet/condition-code](http://hl7.org/fhir/ValueSet/condition-code)"));
codePhrase.setCodeString("192008");
codedText.setDefiningCode(codePhrase);
codedText.setValue("Congenital syphilitic hepatomegaly");
and I got this error:
Exception in thread "main" org.ehrbase.client.exception.WrongStatusCodeException: Wrong Status code. Expected: [200, 201, 204]. Got: 422. Error message: {"error":"Unprocessable Entity","message":"/content[openEHR-EHR-OBSERVATION.externalterm.v0]/data[at0001]/events[at0002]/data[at0003]/items[at0004]/value: Failed to validate DvCodedText{defining_code=[http://hl7.org/fhir/ValueSet/condition-code::192008](http://hl7.org/fhir/ValueSet/condition-code::192008), value=Congenital syphilitic hepatomegaly}, : The value 192008 does not match any option from value set [http://hl7.org/fhir/ValueSet/condition-code](http://hl7.org/fhir/ValueSet/condition-code)"}
---
## Post #8 by @ian.mcnicoll
No - the terminologyID is just as I indicated above - this tells the system that it is a SNOMED CT code.
Can you share the template you are using- preferably as a template fileset?
---
## Post #9 by @Alex_Paris
I can't upload the template fileSet, I send you the .opt
[ExternalTERM.opt|attachment](upload://mGCQfkXBjjm22H2p2JAlro4jOCG.opt) (16.1 KB)
---
## Post #10 by @ian.mcnicoll
That looks correct in terms of the template pointing to the correct Valueset
```xml
terminology://fhir.hl7.org/ValueSet/$expand?url=http://hl7.org/fhir/ValueSet/condition-code
```
Try what I suggested...
```
codePhrase.setTerminologyId(new TerminologyId(“http://snomed.info/sct”));
codePhrase.setCodeString(“192008”);
codedText.setDefiningCode(codePhrase);
codedText.setValue(“Congenital syphilitic hepatomegaly”);
```
---
## Post #11 by @Alex_Paris
I tried what you suggested:
codePhrase.setTerminologyId(new TerminologyId(“http://snomed.info/sct”));
codePhrase.setCodeString(“192008”);
codedText.setDefiningCode(codePhrase);
codedText.setValue(“Congenital syphilitic hepatomegaly”);
and I got the same error:
Exception in thread "main" org.ehrbase.client.exception.WrongStatusCodeException: Wrong Status code. Expected: [200, 201, 204]. Got: 422. Error message: {"error":"Unprocessable Entity","message":"/content[openEHR-EHR-OBSERVATION.externalterm.v0]/data[at0001]/events[at0002]/data[at0003]/items[at0004]/value: Failed to validate DvCodedText{defining_code=[http://snomed.info/sct::192008](http://snomed.info/sct::192008), value=Congenital syphilitic hepatomegaly}, : The value 192008 does not match any option from value set [http://hl7.org/fhir/ValueSet/condition-code](http://hl7.org/fhir/ValueSet/condition-code)"}
---
## Post #12 by @ian.mcnicoll
Is your CDR actually hooked up to a physical FHIR terminology service? That would be a local configuration in your Ehrbase.
The templated constraint is a virtual URI which would have to be resolved to an actual physical FHIR TS which can resolve the is_a relationship within the Valueset.
```terminology://fhir.hl7.org/ValueSet/$expand?url=http://hl7.org/fhir/ValueSet/condition-code```
---
## Post #13 by @Alex_Paris
I have the default configuration in the application.yml:
External Terminology Validation Properties
validation:
external-terminology:
enabled: false
provider:
fhir:
type: FHIR
url: https://r4.ontoserver.csiro.au/fhir/
And I have set in the .env.ehrbase file the variable
VALIDATION_EXTERNAL_TERMINOLOGY_ENABLED=true
to enable the external therminology validation
---
## Post #14 by @admin.in2
Hi Ian,
We want to check that the code we are using is part of a ValueSet that is a SubSet of SNOMED-CT.
My understanding is that if we specify the terminology id as http://snomed.info/sct, the check is done against the full terminology, not the SubSet. Is that correct?
---
## Post #15 by @ian.mcnicoll
> My understanding is that if we specify the terminology id as http://snomed.info/sct, the check is done against the full terminology, not the SubSet. Is that correct?
AFAK that is not correct. In this case 'http://snomed.info/sct'
is just being used as the namespace/identifier for the term you are recording
i.e defining_code=http://snomed.info/sct::192008 = this is term 192008 from SNOMED CT.
It is the constraint in the template that points to you wanting to check that this code is in the ```hl7.org/fhir/ValueSet/condition-code Valueset.``` on the Ontoserver instance
That's all looking correctly setup to me. Perhaps @luis_marco or @birger.haarbrandt can advise? I have not played with the ehrbase/FHIR TS hookup myself.
It is clearly trying to do the validation so the .env is kicking in correctly.
---
## Post #16 by @admin.in2
OK. Understood.
Thanks
---
## Post #17 by @ian.mcnicoll
Try searching on this term.
```
{
"system": "http://snomed.info/sct",
"code": "708094006",
"display": "Acute exacerbation of intrinsic asthma"
},
```
- I could not find the term you looked for in the Valueset returned from Ontoserver - ? there is a paging issue
```
curl --location 'https://r4.ontoserver.csiro.au/fhir//ValueSet/$expand?url=http%3A%2F%2Fhl7.org%2Ffhir%2FValueSet%2Fcondition-code'
```
---
## Post #18 by @ian.mcnicoll
[quote="ian.mcnicoll, post:17, topic:3755"]
`Acute exacerbation of intrinsic asthma`
[/quote]
I cant' get it to work either, sending
```json
"externalterm/externalterm/any_event:0/diagnostico|terminology": "http://snomed.info/sct",
"externalterm/externalterm/any_event:0/diagnostico|value": "708094006",
"externalterm/externalterm/any_event:0/diagnostico|code": "Acute exacerbation of intrinsic asthma",
```
Error:
```
OBSERVATION.externalterm.v0]/data[at0001]/events[at0002]/data[at0003]/items[at0004]/value: Failed to validate DvCodedText{defining_code=SNOMED-CT::Acute exacerbation of intrinsic asthma, value=708094006}, : The value Acute exacerbation of intrinsic asthma does not match any option from value set http://hl7.org/fhir/ValueSet/condition-code"
```
Might be worth reporting on ehrBase Github
---
## Post #19 by @ian.mcnicoll
I think the example given at [ehrBase Terminology validation](https://ehrbase.readthedocs.io/en/latest/08_terminology_validation/index.html#configuration)
is misleading.
It says
```
"value": {
"_type": "DV_CODED_TEXT",
"value": "Buccal",
"defining_code": {
"_type": "CODE_PHRASE",
"terminology_id": {
"_type": "TERMINOLOGY_ID",
"value": "http://hl7.org/fhir/ValueSet/surface"
},
"code_string": "B"
}
}
```
but I think it should be
```
"value": {
"_type": "DV_CODED_TEXT",
"value": "Buccal",
"defining_code": {
"_type": "CODE_PHRASE",
"terminology_id": {
"_type": "TERMINOLOGY_ID",
"value": "http://snomed.info/sct"
},
"code_string": "B"
}
}
```
---
## Post #20 by @Alex_Paris
I think it's not working for you because you've swapped code and value values.
Should be value="Acute exacerbation of intrinsic asthma" and code_string="708094006"
---
## Post #21 by @Alex_Paris
It's definitely as you suggested, with http://snomed.info/sct in the terminology id. Now it's working for me!
Many thanks for your time Ian!
---
## Post #22 by @ian.mcnicoll
Ooops!! Well spotted.
Have you tried querying that data back?
---
## Post #23 by @Alex_Paris
Yes, I have been able to query the data!
---
## Post #24 by @ian.mcnicoll
Can you post the AQL? Just curious!!
---
## Post #25 by @Alex_Paris
I have done it like this:
```
Query> query = Query.buildNativeQuery("select e/ehr_id/value, o/data[at0001]/events[at0002]/data[at0003]/items[at0004]/value/defining_code/code_string from EHR e contains COMPOSITION a [openEHR-EHR-COMPOSITION.externalterm.v0] contains OBSERVATION o [openEHR-EHR-OBSERVATION.externalterm.v0]", UUID.class, String.class);`
List> result = openEhrClient.aqlEndpoint().execute(query);
result.forEach(res->{System.out.println(res.value1() + " "+ res.value2());});
```
---
## Post #26 by @linforest
[quote="Alex_Paris, post:13, topic:3755"]
And I have set in the .env.ehrbase file the variable
VALIDATION_EXTERNAL_TERMINOLOGY_ENABLED=true
to enable the external therminology validation
[/quote]
@Alex_Paris @ian.mcnicoll
Currently, docker compose is used to start the EHRBase and related docker images. Should I rebuild the EHRBase docker image(s) if set the variable to true?
Without rebuilding the EHRBase docker image(s), the start process of EHRBase failed (i.e., Application run failed) and gave me some exception messages like:
```
... Factory method 'externalTerminologyValidator' threw exception with message: At least one external terminology provider must be defined if 'validation.external-validation.enabled' is set to 'true'
```
Thanks
---
## Post #27 by @jake.smolka
Can you post your complete example, i.e. command or docker-compose file used?
Technically, you should not need to rebuild. And the error indicates that the setting went through just fine, but is missing an external terminology provider in the config.
---
## Post #28 by @linforest
Thanks, @jake.smolka
.env.ehrbase
```
SERVER_NODENAME=local.ehrbase.org
SECURITY_AUTHUSER=ehrbase-user
SECURITY_AUTHPASSWORD=SuperSecretPassword
SECURITY_AUTHADMINUSER=ehrbase-admin
SECURITY_AUTHADMINPASSWORD=EvenMoreSecretPassword
SECURITY_OAUTH2USERROLE=USER
SECURITY_OAUTH2ADMINROLE=ADMIN
MANAGEMENT_ENDPOINTS_WEB_EXPOSURE=env,health,info,metrics,prometheus
MANAGEMENT_ENDPOINTS_WEB_BASEPATH=/management
# Modified by Reference: github.com/crs4/openEHR-tool
MANAGEMENT_ENDPOINT_ENV_ENABLED=false
MANAGEMENT_ENDPOINT_HEALTH_ENABLED=false
MANAGEMENT_ENDPOINT_HEALTH_DATASOURCE_ENABLED=false
MANAGEMENT_ENDPOINT_INFO_ENABLED=false
MANAGEMENT_ENDPOINT_METRICS_ENABLED=false
MANAGEMENT_ENDPOINT_PROMETHEUS_ENABLED=false
MANAGEMENT_ENDPOINT_HEALTH_PROBES_ENABLED=false
# MANAGEMENT_ENDPOINT_ENV_SHOWVALUES=ALWAYS
# ADMIN_API_ACTIVE=true
# ADMINAPI_ALLOWDELETEALL=true
VALIDATION_EXTERNAL_TERMINOLOGY_ENABLED=true
```
Related snippet of application.yml in the ehrbase v2.6.0 folder (absolute path: ~/ehrbase-2.6.0/configuration/src/main/resources):
```
# External Terminology Validation Properties
validation:
external-terminology:
enabled: true
fail-on-error: true
provider:
fhir-server-1:
type: fhir
url: https://example.com/fhir
```
Snippet of docker-compose.yml:
```
#
# Minimal setup for a running EHRbase. Contains the server component as well as the required postgres instance.
#
services:
#
# EHRBase container. see `.env.ehrbase` for configuration details.
#
ehrbase:
#image: ${EHRBASE_IMAGE:-ehrbase/ehrbase:next}
image: ehrbase/ehrbase:2.6.0
env_file:
- .env.ehrbase
environment:
...
```
---
## Post #29 by @linforest
Should I set all the External Terminology Validation Properties in the .env.ehrbase file rather than the application.yml? Like the following:
```
# External Terminology Validation Properties
VALIDATION_EXTERNAL_TERMINOLOGY_ENABLED=true
VALIDATION_EXTERNAL_TERMINOLOGY_FAIL_ON_ERROR=true
VALIDATION_EXTERNAL_TERMINOLOGY_PROVIDER_NAME=fhir-server-1
VALIDATION_EXTERNAL_TERMINOLOGY_PROVIDER_TYPE=FHIR
VALIDATION_EXTERNAL_TERMINOLOGY_PROVIDER_URL=https://example.com/fhir
```
---
## Post #30 by @ian.mcnicoll
[quote="linforest, post:28, topic:3755"]
` url: https://example.com/fhir`
[/quote]
Ok - so the issue here is that you need to change this setting to point to an actual FHIR service .
The setting in the .opt is just a virtual URI
```
//fhir.hl7.org/ValueSet/$expand?url=https://example.com/fhir/ValueSet/valueset-exmaple
```
Basivally this part `//fhir.hl7.org` just says this is some kind of FHIR Terminology service - it does not point to an actual service.
What you have to do is setup your Ehrbase instance to point to the physical FHIR service
`url: https://example.com/fhir`
to something like
`url: https://r4.ontoserver.csiro.au/fhir`
EhrBase should then be able to replace the 'virtual part of the .opt uri with the actual endpoint
`https://r4.ontoserver.csiro.au/fhir/ValueSet/$validate?url=https://example.com/fhir/ValueSet/valueset-exmaple` which is what is actually sent to the server
---
## Post #31 by @linforest
[quote="ian.mcnicoll, post:30, topic:3755"]
What you have to do is setup your Ehrbase instance to point to the physical FHIR service
[/quote]
Yes, I did as you suggested. "https://example.com/fhir" is just a dummy url for the actual FHIR server base URL.
---
## Post #32 by @ian.mcnicoll
[quote="linforest, post:28, topic:3755"]
```
validation:
external-terminology:
enabled: true
fail-on-error: true
provider:
fhir-server-1:
type: fhir
url: https://example.com/fhir
```
[/quote]
I might be wrong but to add this setting to .env.ehrbase try these lines
```
VALIDATION_EXTERNAL_TERMINOLOGY_FHIR_SERVER_1_TYPE = fhir
VALIDATION_EXTERNAL_TERMINOLOGY_FHIR_SERVER_1_URL = https://example.com/fhir
```
This is [standard Spring boot 'speak'!!](https://docs.spring.io/spring-boot/reference/features/external-config.html#features.external-config.files)
---
## Post #33 by @linforest
It seems that the cause of the Exceptions is a misspelling of the variable names in the env file. The following is the spelling of variable names from the official documentation.
```
# Configure FHIR Terminology Validation Server
VALIDATION_EXTERNALTERMINOLOGY_ENABLED=true
# If set it must match a spring.security.oauth2.client.registration.[client_name] that needs to be configured
VALIDATION_EXTERNALTERMINOLOGY_PROVIDER_FHIRTERMINOLOGYSERVER_OAUTH2CLIENT=fhir-terminology-client
VALIDATION_EXTERNALTERMINOLOGY_PROVIDER_FHIRTERMINOLOGYSERVER_TYPE=FHIR
VALIDATION_EXTERNALTERMINOLOGY_PROVIDER_FHIRTERMINOLOGYSERVER_URL=http://fhir.localtest.me/fhir/
```
Now, the docker images can be started successfully although the **Get an example Composition from a template** (from the UI of the **openEHR tool**) still doesn't work (i.e., retrieving the valueset).
In addition, I'm wondering how to the provider name in the variable name. @ian.mcnicoll I should try your naming method.
```
...
provider:
fhir-server-1:
...
```
I'm sorry. The following naming doesn't work:
```
VALIDATION_EXTERNALTERMINOLOGY_PROVIDER_FHIRTERMINOLOGYSERVER_FHIR_SERVER_1_TYPE=FHIR
VALIDATION_EXTERNALTERMINOLOGY_PROVIDER_FHIRTERMINOLOGYSERVER_FHIR_SERVER_1_URL=http://fhir.localtest.me/fhir/
```
**Working version**:
```
VALIDATION_EXTERNALTERMINOLOGY_PROVIDER_WHATEVERNAME1_TYPE=FHIR
VALIDATION_EXTERNALTERMINOLOGY_PROVIDER_WHATEVERNAME1_URL=http://fhir.localtest.me/fhir/
```
---
## Post #34 by @linforest
[quote="ian.mcnicoll, post:30, topic:3755"]
The setting in the .opt is just a virtual URI
[/quote]
My setting in the .opt is fine for the tab "form" in the on-line [Archetype Designer](https://tools.openehr.org/designer).

*Successfully reading the expanded valueset (a local valueset for smoking status) from my FHIR Terminology server.*
---
## Post #35 by @ian.mcnicoll
Yes - but that is because AD also resolves the 'virtual Terminology service' in the .opt to an actual server, from a setting provided.

---
## Post #36 by @linforest
[quote="linforest, post:33, topic:3755"]
In addition, I’m wondering how to the provider name in the variable name.
[/quote]
The following naming for the provider name is OK but likely meaningless:
```
VALIDATION_EXTERNALTERMINOLOGY_PROVIDER_FHIRTERMINOLOGYSERVER_NAME=fhir-server-1
```
---
## Post #37 by @linforest
Hi, @jake.smolka. Now, the provider has been successfully set (the EHRBase can be started smoothly without any errors/exceptions). Also, the message about the operation *GET an example Composition ...* (from the openEHR tool) is shown as successful without any error/exception messages. Furthermore, the same is true for the GET operation performed directly in the EHRBase Swagger-UI (status code: 200); in the example Composition generated, it just complains that there is **No example for termínology**:
```
Example Coded Element Name
No example for termínology '//fhir.hl7.org/ValueSet/$expand?url=https://example.com/fhir/ValueSet/valueset-exmaple' available
//fhir.hl7.org/ValueSet/$expand?url=https://example.com/fhir/ValueSet/valueset-exmaple
42
```
Is there any other relevant settings to get coded elements in an example Composition populated?
Thanks.
---
## Post #38 by @linforest
This issue seems to be related to the following codes in the [openEHR_SDK](https://github.com/ehrbase/openEHR_SDK)'s [ExampleGeneratorConfig.java](https://github.com/ehrbase/openEHR_SDK/example-generator/src/main/java/org/ehrbase/openehr/sdk/examplegenerator/ExampleGeneratorConfig.java#L106) :
```
...
public class ExampleGeneratorConfig {
...
static void handleCodePhrase(CodePhrase value, WebTemplateNode node, WebTemplateNode parent) {
Optional codeIn = getInput(node, "code");
selectInputValue(codeIn, 0.)
.map(c ->
Pair.of(codeIn.map(WebTemplateInput::getTerminology).orElse(null), c.getValue()))
.or(() -> {
Optional ehrTerminology = OpenEHRTerminology.lookup(parent, node.getId());
String codeString;
String terminology;
if (ehrTerminology.isPresent()) {
var terms = ehrTerminology.get().getAllTerms();
if (terms.isEmpty()) {
switch (ehrTerminology.get().openEHRGroup) {
case "languages":
terminology = "openehr";
codeString = "de";
break;
default:
terminology = "TODO";
codeString = "TODO";
}
} else {
int i = determineIndex(0., terms.size());
var term = terms.get(i);
codeString = term.getCodeString();
terminology = term.getTerminologyId();
}
} else {
terminology =
codeIn.map(WebTemplateInput::getTerminology).orElse(null);
if ("snomed-ct".equalsIgnoreCase(terminology)) {
codeString = "254626006";
} else {
codeString = "42";
}
}
return Optional.of(Pair.of(terminology, codeString));
})
.ifPresent(t -> {
value.setCodeString(t.getRight());
value.setTerminologyId(new TerminologyId(
Optional.ofNullable(t.getLeft()).orElse(null)));
});
}
```
---
## Post #39 by @vidi42
@linforest EHRbase uses the [openEHR_SDK to generate examples](https://github.com/ehrbase/openEHR_SDK/blob/5d182a74c4b648ce2bcf31b8af72ad1bd0bb3035/example-generator/src/main/java/org/ehrbase/openehr/sdk/examplegenerator/ExampleGeneratorConfig.java#L685) based on templates. However for terminology we only support a snomed-ct example for now. No FHIR terminology support for example generation.
I believe it could be useful to extend the example generation in the future with more terminology support, but, for now, keep in mind this only generates a basic example structure.
So we have this on our radar and evaluate it, could you open an Enhancement issue here https://github.com/ehrbase/openEHR_SDK/issues?
---
## Post #40 by @linforest
Hi, [Alex](https://discourse.openehr.org/u/vidi42). Great to hear from you. I understand its status now. Thank you so much for your reply. And I'll try to open an issue on this.
BTW, you know, there are dozens of such coded elements in one of my templates so it's quite time-consuming and verbose to manually author even a single example Composition instance. Indeed that would be pretty helpful and efficient if the generator got improved with more terminology support, especially for FHIR Terminology Service.
---
## Post #41 by @vidi42
@linforest Thank you for the issue report and the feedback. I will bring this with me to the team.
---
**Canonical:** https://discourse.openehr.org/t/how-to-set-external-terminology-validation/3755
**Original content:** https://discourse.openehr.org/t/how-to-set-external-terminology-validation/3755