New Zealand Health Terminology Service (NZHTS) Implementation Guide
0.9.0 - draft
New Zealand Health Terminology Service (NZHTS) Implementation Guide - Local Development build (v0.9.0) built by the FHIR (HL7® FHIR® Standard) Build Tools. See the Directory of published versions
NZHTS is a registered participant in the HL7 FHIR terminology ecosystem, and has been declared as the authoritative server for terminology artifacts used in NZ such as the NZ edition of SNOMED CT. That declaration allows the IG publisher to resolve NZ terminology against NZHTS automatically.
This page provides background on how the terminology ecosystem works: the actors involved, how the IG Publisher decides which terminology server to call, and what happens end to end during a build. It is not strictly necessary to understand how the terminology co-ordination service and registry work in detail, but it is helpful when building IGs to understand at a high level where terminology is being sourced, validated, and expanded from. The full documentation is available in the Github terminology server registry docs and accompanying FHIR IG.
The Publisher consults a co-ordination service for information about terminology artifacts included in an IG and then calls the appropriate registered servers to $validate/$expand/$lookup as required. NZHTS is one of those registered servers, reached through the registry. The diagram below shows the various componenents and how they relate to each other.
flowchart LR
IGSource["IG source"]
FHIRPackages["FHIR packages<br/>(local cache, registry, FHIR Core,<br/>THO, FHIR extensions,<br/>dependencies)"]
Publisher["IG Publisher /<br/>Validator"]
Coordinator["Co-ordination service<br/>(tx.fhir.org/tx-reg)"]
Registry["Terminology ecosystem<br/>registry (server registrations,<br/>authority declarations)"]
subgraph RegisteredServers["Registered terminology servers"]
direction TB
ServerGateway[" "]
SharedHL7["Shared HL7<br/>terminology server<br/>(tx.fhir.org/r4)"]
NZHTS["NZHTS<br/>(nzhts.digital.health.<br/>nz/fhir)"]
OtherServers["AU, CA, DE, EU, etc."]
ServerGateway ~~~ SharedHL7
SharedHL7 ~~~ NZHTS
NZHTS ~~~ OtherServers
end
IGSource -->|"Inputs"| Publisher
FHIRPackages --> Publisher
Publisher <-->|"Look up terminology server to use for each<br/>$expand, $validate-code, $lookup, etc."| Coordinator
Coordinator <--> Registry
Publisher <-->|"Terminology requests routed to the appropriate server<br/>($expand, $validate-code, $lookup)"| ServerGateway
style RegisteredServers fill:none,stroke:#333,stroke-width:2px,stroke-dasharray: 8 6
style ServerGateway fill:none,stroke:none,color:transparent
tx.fhir.org/tx-reg) is the directory/lookup service. Given a code system or value set URL and a FHIR version, it answers the question "which server should I ask?"tx.fhir.org/r4), NZHTS, and the equivalent national and regional servers for AU, CA, DE, the EU and others.Whenever the Publisher hits coded content it needs to make a decision about, it works through the sequence below. Calling a terminology server is the last resort; the Publisher tries progressively more expensive options in order:
tx-reg with the FHIR version, the code system or value set URL, and usage=publication, asking which server to use.The response then determines routing. If a server has declared authority for that terminology, its endpoint is used — this is the path NZ SNOMED CT and NZ code systems take to NZHTS. If there is no authoritative server but there are candidates, one is chosen, typically the primary tx.fhir.org. If neither is returned, the Publisher falls back to whatever primary tx server the build was configured with, or reports the terminology as unresolved.
Once an endpoint is selected, the actual FHIR operation is issued: ValueSet/$validate-code, CodeSystem/$validate-code, ValueSet/$expand or CodeSystem/$lookup and the result is cached and turned into QA output. Note that $expand can return a "too costly" response rather than an expansion for a large or open-ended value set.
---
title: IG Publisher terminology validation
---
flowchart LR
A["Need terminology decision<br/>system/valueSet/version"] --> B{"Already in<br/>tx cache?"}
B -- yes --> C["Use cached Parameters<br/>or expansion"]
B -- no --> D{"Can local/package<br/>artifacts answer safely?"}
D -- yes --> E["Validate locally<br/>or use local expansion"]
D -- no --> F["Ask tx-reg<br/>resolve(fhirVersion, url/valueSet, usage=publication)"]
F --> G{"Authoritative<br/>server returned?"}
G -- yes --> H["Use authoritative endpoint"]
G -- no --> I{"Candidate servers<br/>returned?"}
I -- yes --> J["Choose candidate<br/>often primary tx.fhir.org"]
I -- no --> K["Use configured primary tx server<br/>or report unresolved terminology"]
H --> L["Call FHIR terminology operation"]
J --> L
K --> L
L --> M{"Operation type"}
subgraph Ops[" "]
direction TB
M --> N["ValueSet/$validate-code"]
M --> O["CodeSystem/$validate-code"]
M --> P["ValueSet/$expand"]
M --> Q["CodeSystem/$lookup"]
end
N --> R["Result, messages, display"]
O --> R
P --> S["Expansion or too-costly/error"]
Q --> T["Display, version, properties"]
R --> U["Cache result + emit QA issues"]
S --> U
T --> U
The sequence diagram below shows the decision logic for terminology resolution and validation in the context of a complete build.
The build starts with package loading and the structural work — snapshot generation, narratives, indexes and profile validation. Terminology resolution then runs as a loop over every piece of bound coded content, applying the cache / local / registry sequence described above. A single IG can generate a very large number of these checks, which is why cache behaviour has such a visible effect on build times.
Each terminology response is converted into errors, warnings or informational messages, and surfaced in three QA artefacts worth knowing about:
qa.html — the overall build QA report, including terminology-derived errors and warnings alongside everything else.qa-tx.html — the terminology-specific report. This is the file to open when you are debugging why a code will not validate or a value set will not expand.qa-txservers.html — a summary of which terminology servers were actually contacted during the build. For an NZ IG, this is the quickest way to confirm that NZ content genuinely resolved to NZHTS rather than silently falling back to the primary server.sequenceDiagram
autonumber
participant Author as IG author / CI
participant Pub as IG Publisher
participant Pkg as FHIR package cache / package registry
participant TxReg as tx.fhir.org/tx-reg
participant Tx as tx.fhir.org primary endpoint
participant Other as Authoritative/candidate ecosystem server
participant QA as QA outputs
Author->>Pub: Run _genonce / CI build<br/>-ig ig.json -tx tx.fhir.org
Pub->>Pkg: Load core + dependency packages
Pkg-->>Pub: StructureDefinitions, ValueSets, CodeSystems, etc.
Pub->>Pub: Generate snapshots, narratives, indexes
Pub->>Pub: Validate profiles and resources
loop For bound coded content / ValueSets
Pub->>Pub: Check local tx cache
alt Cache miss and local artifacts insufficient
Pub->>TxReg: Resolve CodeSystem/ValueSet<br/>FHIR version + usage=publication
TxReg-->>Pub: authoritative/candidate server choices
alt Authoritative/candidate selected
Pub->>Other: $validate-code / $expand / $lookup
Other-->>Pub: Parameters / ValueSet / OperationOutcome
else Use primary
Pub->>Tx: $validate-code / $expand / $lookup
Tx-->>Pub: Parameters / ValueSet / OperationOutcome
end
Pub->>Pub: Cache response
end
Pub->>Pub: Convert tx result into errors/warnings/info
end
Pub->>QA: Generate qa.html
Pub->>QA: Generate qa-tx.html
Pub->>QA: Generate qa-txservers.html