Skip to main content

Implementation Guides

An implementation guide (IG) such as US Core is published as a FHIR package: an npm-style .tgz holding its profiles, extensions, ValueSets, CodeSystems and SearchParameters. Haste Health installs a package into a project in one step, either by name from the FHIR package registry or from a .tgz you upload.

Once a package is installed:

  • its profiles are enforced on resources that name them in meta.profile (see Profiling & Validation),
  • its SearchParameters can be searched, like any project SearchParameter,
  • its ValueSets, CodeSystems, ConceptMaps and NamingSystems are there for validation and terminology operations.

Installing a package​

From the admin app​

Open Packages in the project console's sidebar (/packages). Type one or more packages as name@version, or choose a .tgz, and press Install. The page lists what was installed, what was skipped and why, and the packages already in the project, each with an Uninstall button.

From the CLI​

# From the registry, with the packages it depends on
haste-health package install hl7.fhir.us.core@6.1.0

# The newest 6.1 patch, or the latest version
haste-health package install hl7.fhir.us.core@6.1.x
haste-health package install hl7.fhir.us.core

# A tarball, or a folder holding package.json (it is packed for you)
haste-health package install ./hl7.fhir.us.core-6.1.0.tgz
haste-health package install ./my-ig/package

# What is installed, and removing one
haste-health package list
haste-health package uninstall hl7.fhir.us.core

install takes --no-dependencies to install only the packages given, --examples to install their example resources as well, and --json to print the server's response. The CLI installs into the project of its active profile (see Setting Up the CLI).

With the API​

Both are operations on ImplementationGuide: $install and $uninstall.

POST /w/{tenant}/{project}/api/v1/fhir/r4/ImplementationGuide/$install
Content-Type: application/fhir+json

{
"resourceType": "Parameters",
"parameter": [
{ "name": "package", "valueString": "hl7.fhir.us.core@6.1.0" }
]
}
ParameterTypeDefaultWhat it does
packagestring, repeatingA package from the registry: name@version (or name#version), name@6.1.x for the newest patch, or name alone for the latest version.
npmContentbase64Binary, repeatingA package .tgz, base64 encoded. Its dependencies are looked for among the other uploads first, then in the registry.
dependenciesbooleantrueAlso install the packages these depend on.
examplesbooleanfalseAlso install the example resources of the packages named or uploaded.

The response is a Parameters with one package entry for every package considered, the ones asked for and their dependencies:

{
"resourceType": "Parameters",
"parameter": [
{
"name": "package",
"part": [
{ "name": "name", "valueString": "hl7.fhir.us.core" },
{ "name": "version", "valueString": "6.1.0" },
{ "name": "status", "valueCode": "installed" },
{ "name": "resources", "valueInteger": 206 }
]
},
{
"name": "package",
"part": [
{ "name": "name", "valueString": "hl7.terminology.r4" },
{ "name": "version", "valueString": "5.0.0" },
{ "name": "status", "valueCode": "skipped" },
{ "name": "reason", "valueString": "Not installed as a dependency, as it is one of the large packages this server skips (packages.skip_dependencies). Install it by name to include it." }
]
}
]
}

status is installed, updated (it replaced an installed version, given in previousVersion) or skipped (see reason). An outcome OperationOutcome carries warnings about single resources that were not installed.

$uninstall takes the package name, and optionally the version you expect to be installed (nothing is removed if another version is):

POST /w/{tenant}/{project}/api/v1/fhir/r4/ImplementationGuide/$uninstall
Content-Type: application/fhir+json

{
"resourceType": "Parameters",
"parameter": [{ "name": "name", "valueString": "hl7.fhir.us.core" }]
}

What gets installed​

From each package, Haste Health installs its StructureDefinitions, ValueSets, CodeSystems, SearchParameters, ConceptMaps and NamingSystems. Other resources in the package are left out, apart from its examples when you ask for them.

  • Ids are kept. Each resource is written with the id it has in the package, so StructureDefinition/us-core-patient is at that address in your project.
  • Each resource is tagged with the package it came from: a meta.tag with system https://haste.health/fhir/CodeSystem/fhir-package, the package name as its code and the package version as its version. Search for a package's resources with _tag=https://haste.health/fhir/CodeSystem/fhir-package|hl7.fhir.us.core.
  • Each package is recorded as an ImplementationGuide whose id is the package name, with packageId, version, and the resources it installed under definition.resource. The package's own ImplementationGuide is used for the record when it has one.
  • One transaction. A package's resources, the resources an upgrade removes and the records are written in one transaction: an install either completes or changes nothing.
  • Examples are written after that, in their own batch, so an example that fails validation is reported as a warning rather than undoing the install. Examples that would configure the server (OperationDefinitions, SearchParameters, Subscriptions, access policies, users, clients and the like) are never installed.
  • Your own resources are safe. If a resource with the same id already exists, it is replaced only when the same package installed it, or when it is untagged and has the same canonical url (an earlier hand-loaded copy of the same profile). Otherwise the package's resource is skipped with a warning.

Dependencies​

With dependencies on (the default), the packages a package depends on are installed too, and the packages those depend on, and so on. When two packages ask for different versions of the same dependency, the one closest to the packages you named wins.

Some dependencies are skipped:

  • The FHIR core packages (hl7.fhir.r4.core and its .examples, .expansions and .elements) are built into the server.
  • Large terminology and cross-version packages hold thousands of resources most projects never use: hl7.terminology, hl7.terminology.r4, hl7.terminology.r5, us.nlm.vsac, us.cdc.phinvads, and the cross-version extensions hl7.fhir.uv.xver-r5.r4, hl7.fhir.uv.xver-r4b.r4, hl7.fhir.uv.xver-r3.r4 and hl7.fhir.uv.xver-r2.r4 (US Core 9.0.0 and SDC 4.0.0 depend on the 150 MB xver-r5.r4). Name one directly to install it: hl7.terminology.r4 and the cross-version packages fit the default limits, while us.nlm.vsac is larger and needs them raised (below). The list is configurable.
  • A dependency that is already installed, in any version, is left as it is. Name it directly to upgrade it.
  • A dependency that cannot be fetched is skipped with the reason; the packages that depend on it still install.

Each package name is considered once, so a cycle of dependencies ends. An install as a whole is bounded too: by default it fetches or uploads at most 50 packages, and they unpack to at most 200 MiB together, dependencies of dependencies included. The largest common IGs fit with room to spare: Da Vinci PDex 2.2.0 with its dependencies is 16 packages and 114 MB, QI-Core 7.0.2 is 89 MB, US Core 9.0.0 is 72 MB. Past either limit the whole install is refused with 422 before anything is written; install fewer packages at once, or turn dependencies off.

Upgrading and uninstalling​

A project holds one version of each package. Installing a package that is already installed replaces it: the new version's resources are written, and the resources the old version installed that the new one no longer has are deleted. The response reports it as updated, with the version it replaced.

Uninstalling deletes the resources the package installed and its ImplementationGuide record. Packages it depends on stay installed; uninstall them separately if nothing else needs them.

FHIR versions​

Haste Health serves FHIR R4, so it installs packages for R4: those whose package.json lists a 4.0.x version in fhirVersions, or lists none. A package for another version is refused, or skipped when it is a dependency. Some R4 packages, such as hl7.fhir.uv.extensions.r4 1.0.0, contain StructureDefinitions that name a later FHIR version; these are installed as R4 and the response says so in a warning.

Limits and configuration​

Packages are fetched from the registry by the server. The [packages] section of the configuration sets where from, what is skipped and how much one install may take:

KeyDefaultWhat it does
packages.registry_urlhttps://packages.fhir.orgThe package registry. Set it to an empty string to turn off fetching, so packages can only be uploaded.
packages.skip_dependenciesThe terminology and cross-version packages abovePackages not installed as dependencies.
packages.max_package_bytes20 MiBLargest package download or upload, compressed.
packages.max_files20000Most files in one package.
packages.max_install_packages50Most packages one install fetches or uploads, dependencies included. A fetch that fails still counts.
packages.max_install_bytes200 MiBMost the packages of one install may unpack to together, uploads included. It is checked while unpacking, so a package past it is never read whole.
packages.max_concurrent_installs1Installs one server runs at once. Another is refused with 429 until it finishes.
packages.free_tier_install_interval_seconds120How often one Free tier tenant may start an install. Another within this time is refused with 429. 0 turns the wait off.
packages.free_tier_shared_install_interval_seconds60How often any Free tier tenant may start an install, all of them together, so Free tier installs cannot keep the install slot busy. Set it well above how long one install takes. 0 turns the wait off.

An install holds its packages in memory while it writes them in one transaction; its peak is about four times what they unpack to, so max_install_bytes times max_concurrent_installs times four bounds what installs can take from the server, however many requests arrive at once.

The server fetches from that registry and nowhere else. Callers name packages and never give a URL, including for the dependencies an uploaded package lists. The registry must be an https URL, and a redirect is followed only while it stays on the registry's scheme, host and port. A private mirror can take credentials in the URL (https://user:password@mirror.example.org); they are never shown in error messages.

An uploaded .tgz travels inside the request, base64 encoded (a third larger), so it is also bound by max_request_body_size (4 MB by default). Most IGs are well under that (US Core 6.1.0 is 1.6 MB); install larger ones by name, or raise the limit.

Installing writes through the FHIR API as the caller, so it needs permission to write the resource types it installs, and it counts toward the project's limits like any other write. On the Free tier (the Developer plan) a tenant may start one install every 2 minutes and the server starts at most one Free tier install a minute across all tenants, and a package's SearchParameters are not installed, as the plan allows none; the response's outcome says how many were left out.

Related Documentation: