FHIR Profiling Guidelines for FHIR R4

Uit informatiestandaarden
Versie door Jorn Duwel (overleg | bijdragen) op 3 feb 2021 om 14:34 (Fixing invalid section link)
Ga naar: navigatie, zoeken

1 Introduction

This page lays out the conventions for creating FHIR profiles and associated conformance resources within Nictiz. These guidelines are specifically aimed at FHIR R4; for the STU3 profiling work, a separate document exists.

This page is titled "profiling guidelines", but actually addresses all conformance resources (profiles, extensions, value sets, code systems, CapabilityStatements) and associated examples. We use these terms somewhat interchangeable throughout this document; 'profile' can usually be read as 'the whole set of conformance resources'.

2 Open vs. closed world modeling

When profiling, an "open world" or a "closed world" model can be chosen. The former means that the profile only allows the elements to be used specified by the functional model, with all the restrictions from the functional model. The latter means that the profile can accommodate the elements specified by the functional model, but doesn't impose further restrictions.

We adopt the "open world" modeling approach to aid re-usability beyond the known use cases. When restrictions are deemed necessary for a specific use case, it will be added to the information standard specific profiles.

× Open Closed
  • Forward compatibility
  • Modelers don't have to think about what you shouldn't support, only what must be supported
  • Implementers can fit more data, even if it's not in specified explicitly bu the profile
  • Implementers, don't have to support all elements that maybe, someday could be used, according to the model
  • Model becomes more specific
  • Model becomes smaller and more straightforward
  • More implementer feedback, about elements they want to support, but currently can't
  • Implementers, have to support all optional elements that maybe, someday could be used, according to the model
  • Model becomes more vague,
  • Model becomes larger and less straightforward about what should actually be supported, and what can optionally be supported
  • Less implementer feedback: elements they want to send can be easier 'hacked' in a not yet explicitly specified element. Model won't be improved.
  • More versions of models, after more elements have to be supported
  • No forward compatibility, only backwards
  • Implementers have to wait for a new version of the model, if they want to support elements, that are currently not in scope.

2.1 General guidelines for open world modeling

We only profile elements, cardinalities and bindings that require profiling. We leave other elements, cardinalities and bindings as-is.

2.2 Cardinality

The functional description will specify the cardinality for each concept as a minimum required and maximum allowed number of times it may occur, which is the same mechanism as in FHIR. However, one needs to be careful as the cardinality can only be restricted in derived profiles, and never widened. Being too strict could thus hinder the re-use of these profiles. This is especially true for cardinalities in zibs, which should be interpreted as 'purely conceptual'; a use case might allow for data that conceptually always should be there to be absent in practice.

For zib profiles:

    • A minimum of 0 or 1 will be profiled as 0.
    • A maximum (1, n, *) will be profiled as-is.

For nl-core profiles:

  • No further restrictions are added, as these profiles only cover the currently known use cases. Adding restrictions here would hinder as yet unknown of undefined use cases.

For information standard specific profiles:

  • If the corresponding zib has a minimum of 1 and the use case doesn't contradict this, the minimum will be profiled here as 1.
  • Cardinalities may be further restricted if the use case defines this.

2.3 Constraining references

Concepts in a functional description oftentimes refer to each other; e.g. most clinical concepts will refer to the concept of a Patient. In FHIR these connections are realized using the reference datatype, which allow to specify the target (base resource of profile) as well. For example, a profile representing the zib Problem could set the target of the .subject element to the profile representing the zib Patient.

However, setting the target explicitly means a restriction of the allowed targets, which runs counter to the principles of open world modelling. On the other hand, specifying a dedicated profile provides useful guidance on how to handle this profile. To address both concerns, the target profile will be added next to the base resource.For example, the Condition resource allows Patient and Group as target in the .subject element. When profiling the zib Problem, the the profile representing the zib Patient will be added as a third option.

3 Functional model as base

Most, if not all, conformance resources are based on an underlying functional model. The functional model is the specification to which the conformance resources should adhere.

The basis for most other functional models is formed by the 'zibs' ('Zorginformatiebouwstenen'), in English also known as are Clinical Information Models (CIMs), Health and Care Information Models (HCIMs) or Clinical Building Blocks (CBB) -- we will use the Dutch term 'zib' for all profiling work as it has become a recognizable term over the past years. The zibs are defined by the program ‘Registratie aan de bron’ (Data capture at the point of care) and provide a foundation of use case neutral building blocks from which use cases can be built. The formal definition of the zibs can be found on the zibs wiki

Use cases or information standards use and refine those zibs that are relevant to the situation. The formal specification for these information standards can usually be found in Nictiz' instance of ART-DECOR.

3.1 Layering: zibs, nl-core profiles and information standard specific profiles

The profiles and other conformance resources align to this layering of information standards. We recognize three levels of profiles:

zib profiles
profiles that represent the zib as faithfully as possible
nl-core profiles
profiles derived from the zib profiles that that might be enriched by concepts from the different use cases that need the zib. See #The nl-core layer for more information.
information standard specific profiles
optional derived profiles from the nl-core profiles that further restrict or enhance these profiles for a specific use case.

3.2 The nl-core layer

The goal of the nl-core layer is to ensure that similar concepts defined at the use case level are implemented in a uniform way at the FHIR level. Whether the concept is used by a single or multiple use cases is irrelevant – adopting it at the intermediate nl-core level provides clear guidance to future use.

On the other hand, concepts defined at the intermediate level are only of value if they can be reused across situations. Therefore, it should be investigated how the concept can be created in a reusable way before it is implemented at the nl-core level. If there is a vanishingly small opportunity for reuse, then it is best to define it at the use case level to avoid clutter at the nl-core level. In practice, this means:

  • Extensions from use cases should usually be generalized and added to the nl-core layer.
  • Adding reference types to specific profiles (see #Constraining references) should usually be done at the nl-core layer.
  • Cardinalities are usually determined by the zibs and further restricted by the use cases, so it makes little sense to implement them at the nl-core layer. These should normally be implemented at the use case layer. Also see #Cardinality.
  • Mappings to the functional specifications for use cases (see #Associating the functional definition to StructureDefinitions) are by definition use case specific and should be added at the use case layer.
  • Bindings to ValueSets (see #ValueSet binding) are usually use case specific, but might be added at the nl-core layer.
  • SearchParameters should usually be generalized and added to the nl-core layer.

3.3 Associating the functional definition to StructureDefinitions

Any StructureDefinition that profiles a Resource does so because there is some kind of logical definition dictating how. Profiles SHALL have a traceable relationship with their functional counterpart(s).

The FHIR specification contains several solutions for this problem, ConceptMap (>=STU1), StructureMap (>=STU3), ElementDefinition.mapping. Neither of these solutions are mature and cover our use case.

  • ConceptMap: works best for value sets and codes.
  • StructureMap: overcomplicated and unclear how to apply and whether or not this has a future.
  • ElementDefinition.mapping: is a free text mapping inside the profile. This means we cannot add mappings to profiles from third parties without updating their resource.

3.3.1 Current implementation

We use the mapping elements in profiles to map functional elements to resource elements. Functional elements are referenced based on their id in the functional model. The mapping SHALL resolve to a description of the functional model. For zibs, this SHOULD be the English page on zibs.nl.

When slicing, the mapping is made on the content of the slice, not the slice itself (see also #Placing-Info).

On the root element of the StructureDefinition, the mapping should thus be defined as:

    <identity value="zib-medicationagreement-v1.2-2020EN" />
    <uri value="https://zibs.nl/wiki/MedicationAgreement-v1.2(2020EN)" />
    <name value="zib MedicationAgreement-v1.2(2020EN)" />

A specific element can then be mapped using:

<element id="MedicationRequest.extension:usageDuration">
    <path value="MedicationRequest.extension" />
        <identity value="zib-medicationagreement-v1.2-2020EN" />
        <map value="NL-CM:9.6.19936" />
        <comment value="PeriodOfUse" />

4 Versioning

In general terms, FHIR conformance resources could be affected at several different layers:

  1. The version of the package that the conformance resources reside in: versioned according to SemVer 2.0.
  2. The version of the conformance resource themselves (StructureDefinition.version): used to indicate the business version to the user, without strict specifications.
  3. The FHIR version (StructureDefinition.fhirVersion): this document is specifically aimed at FHIR R4, meaning this element will be fixed on 4.x.
  4. The version of the underlying data model.

Regarding point 1 and 2: Nictiz uses the package level as the main versioning mechanism. As a result, the conformance resources within the package are not individually versioned; they should be regarded as a consistent set. To identify the package version a conformance resource, its version number will be set to the package version.

Regarding point 4: the life cycle of the underlying data model is not reflected directly in the version number of the conformance resources, but a change in de the underlying data could result in a change in one or more of the conformance resources. In this case, the normal SemVer rules will determine what happens; if some of the conformance resources need to be changed in a backwards compatible way, a new patch release of the package should be made, if major functionality is added, a new minor version of the package should be released, etc. When a new version of the underlying data model reflects a fundamental change, the choice can be made to create a new package under a different name rather than a new version (eg. each zib releases will have their own package).

Version updates of conformance resources normally do not affect their canonical URI. Any resource that references another resource normally does so without a version indicator (uri|version). Instead, this is handled at the package level; reference targets either reside within the same package or in a versioned package that has been added as a dependency.

5 Mapping semantic codes to profiles

Oftentimes a functional concept has an equivalent FHIR element, e.g. a 'comment' in the functional description maps in FHIR to the Resource.comment element. When this is not the case, a code (usually SNOMED or LOINC) is needed to add the proper definition to the FHIR resource, usually using the Resource.code element. For example, the root concept of an Observation is unknown unless it is defined by the .code element, and when components are used in an Observation, each Observation.component needs to be defined using an individual .code element. These codes should be provided by the functional description (for zibs this is the DefinitionCode).

These codes are profiled as required elements using a ElementDefinition.pattern on the element that should contain the code. This allows to add additional codings on the same element.

6 Slicing

Elements are sliced for two reasons:

  1. To specify different requirements for repetitions of an element.
  2. To allow other uses of a base element than what is required by the functional specification, e.g. the reuse of an .identifier next to the profiled .identifier.

Slicing can often occur on different levels within an element, e.g. when the element is of type CodeableConcept, a slice can be made on the element itself or on the child element of type Coding (.element.coding). In general, slicing will occur on the highest level possible, thus on the element itself in the example above. Note that this is only possible for repeating elements (max cardinality > 1). When an element of type CodeableConcept does not repeat, the Coding element can be sliced, but this is discouraged as this is often not what is meant; when .coding repeats within a single element of type CodeableConcept, it must have the same semantic meaning although some granularity difference is accepted (eg. when communicating the same concept in different code systems).

In general, the slice discriminator is set to discriminator.type = value and discriminator.path to the path where the discriminator value is located (if it is the root element, it should be noted as $this). The sliced element gets a pattern or a required ValueSet binding on the location of the path. No further cardinality constrains are added in the sliced element that correspond with the pattern[x] as they are made mandatory by the pattern. These general slicing guidelines apply to the following situations. See this page for examples in XML:

  • Mapping semantic codes to profiles requires the presence of the semantic code while leaving the option to use the element for other concepts, e.g the zib LaboratoryTestResultCode profile uses Observation.category for a sematic code that represents the zib and to map the zib concept ResultType.
  • Identifier systems are always defined on a sliced .identifier, even if there is only one defined.

Other forms of slicing that are common (Forge sets these slicing details by default):

  • A concept is mapped to one or multiple types of a polymorphic element, e.g. Observation.value[x]. The mapping and functional description are placed on the slice with the matching data type(s).
  • Adding an extension slices the .extension element that is discriminated by the value on extension.url.

7 ValueSet binding

7.1 Binding strength

In general, the binding strength provided in the functional description is used as binding strength in the profile.

7.2 Binding multiple ValueSets

The functional model might require multiple valuesets to be used for some data element, eg. when offering the choice between multiple code systems. However, FHIR allows to bind just one ValueSet to an element. There are two strategies to handle this situation:

  1. Create and bind a combined ValueSet that encompasses all the ValueSets defined in the functional model.
  2. Create slices for each ValueSet binding.

The use of combined ValueSets is the preferred approach. Although the use of slices would make the different concepts visible in the profiles, this strategy doesn’t allow for overlapping ValueSets (which doesn’t make much sense semantically but happens for example when the different ValueSets include the same NullFlavor codes). It is also less straightforward for derived profiles to expand or restrict the base ValueSet when using slices, be (if the binding strength permits it and it makes sense semantically) by binding a new ValueSet.

Option 2 should be used if there are different requirements for the ValueSet bindings.

7.3 Handling conflicts with base bindings

For FHIR base resource elements with datatype code and binding required it may be that the functional description uses other/additional codes to specialize the FHIR codes. To conform to FHIR and the functional description:

  • The ValueSet from the functional description will be bound with the binding strength of the functional concept using the code-specification extension. The extension slice is named after the full English name of the value set according to the functional description.
  • Mapping to the concepts of the functional description is applied both to the FHIR element and the extension.
  • The mapping will be documented in a ConceptMap, which will be linked using the extension permitted-value-conceptmap extension.

8 Extensions

Sometimes a concept from the functional model cannot be implemented using the building blocks FHIR offers by default. In this case, an extension might be used to implement such concept. Keep in mind that extensions are often seen as a burden for implementers:

  1. If it possible to model the concept (cleanly) without an extension, this is usually the preferred way.
  2. If that's not possible, check if HL7 provides an extension to implements the concept.
  3. If that's not possible, try to create an extension in a reusable way (or reuse a previously defined extension).
  4. If that's not possible, create an extension specific for the profile.

Usually the mappings to the functional model, bindings to specific ValueSets and any functional descriptions will be added when the extension is used within a profile. When the extension pertains to a particular profile, this information SHALL be added to the StructureDefinition of the ValueSet.

9 Practical guidelines

9.1 Identity of artifacts

9.1.1 Canonical URL, id, name and title

Conformance resources can have multiple types of identifying information, which are related at some level:

The canonical URL, which is the external identifier for conformance resources. All conformance resources SHALL have a canonical URL. This URL is preferably resolvable but does not have to be processable. Canonical URL's are about the identity of artifacts, not necessarily about retrieval location. Canonical URLs aren't meant to be human recognizable.
This should align with the latter part of the canonical URL.
A recognizable name that is still computer processable.
A recognizable title purely for human consumption.

URIs for the latter (for artifacts living in ART-DECOR) are described in ART-DECOR FHIR_URIs. Profiles and extensions

  • The .id will be constructed in the following way:
    • For profiles
      • representing a functional building block:
        • zib profiles:zib-[English zib name]
        • nl-core profiles:nl-core-[English zib name]
        • standard specific:[project prefix]-[concept name]
      • representing a particular concept of a functional building block: [profile id]-[English concept name]
    • For extensions:
      • pertaining to 1 profile:ext-[profile id]-[English concept name]
      • pertaining to multiple profiles, or not pertaining to specific profiles and generally applicable:
        • if the use context is a single resource:ext-[resource]-[purpose]
        • otherwise:ext-[purpose]
  • The canonical URL will then be created as: http://nictiz.nl/fhir/StructureDefintion/[id]
  • The name will be the .id capitalized, with hyphens removed.
  • The title will generally be the .id with hyphens replaced by spaces.


  • [project prefix] is preferably the same as its matching ART-DECOR project prefix
  • [purpose] and [English concept name] are generally a PascalCased name joining words together, with the first letter of every wordcapitalized. ValueSets

  • For value sets as specified on ART-DECOR, the id will be:[value set OID]--[effective date as yyyymmddhhmmss]
  • The canonical URL will then be created as: http://decor.nictiz.nl/fhir/ValueSet/[id]
  • Both the name and title will be name of the value set (usually in Dutch). ConceptMaps

  • The id will be constructed as: [source ValueSet.name]-to-[target ValueSet.name]
  • The canonical URL will then be: http://nictiz.nl/fhir/ConceptMap/[id]
  • The name will be constructed as: [source ValueSet.name]_to_[target ValueSet.name]
  • The title will be constructed as: [source ValueSet.name] to [target ValueSet.name]

9.1.2 Folder structure and file name

resources/terminology/[Dutch name]-[id].xml
examples/[profile id]-[serial number, two digits].xml

9.2 Metadata

9.2.1 Metadata on the StructureDefinition root

  • version: see #Versioning
  • status: as applicable (normally draft or active)
  • publisher: Nictiz
  • contact:
    • name: Nictiz
    • telecom:
      • system: email
      • value: info@nictiz.nl
      • use: work
  • description:
    • For profiles:
      • For zib profiles: the 'Concept' section from the zib.
      • For nl-core profiles: left blank to inherit the description from the zib profile.
      • For standard specific profiles: as applicable.
    • For extensions:
      • A description of what the extension is for.
  • purpose:
    • For profiles:
      • For zib profiles: This [resource type] resource represents the Dutch [zib ('Zorginformatiebouwsteen', i.e. Health and Care Information Model) [English zib name] [version]([release])]([link to the English zib page on zibs.nl]).
      • For nl-core profiles: A derived profile from [[id of zib profile]]([canonical of zib profile]) to provide a version better suited for implementation purposes. This profile augments the base profile with elements found in the various use cases that have adopted the zib.
      • For standard specific profiles: a description with a reference to the base profile, with an explanation of why it has been added.
    • For extensions:
      • For extension representing a specific concept: This extension represents the [concept name] of [name of the building block]], followed by a link to the functional description.
      • For other extensions this will likely be absent.
  • copyright: Copyright and related rights waived via CC0, https://creativecommons.org/publicdomain/zero/1.0/. This does not apply to information from third parties, for example a medical terminology system. The implementer alone is responsible for identifying and obtaining any necessary licenses or authorizations to utilize third party IP in connection with the specification or otherwise.
  • mapping: see #Associating_the_functional_definition_to_StructureDefinitions
  • abstract: usually false, but may be set to true when this profile is to be used only as a base profile from which other profiles should be derived.
  • comment: when special guidance on the use of this profile is needed, it will be placed here. For example: when this profile has a (non-trivial) relationship to other profiles, when a concept of the functional description is mapped over multiple elements, etc.

9.2.2 Metadata for elements

For elements that map to zibs:

  • The English name from the zib concept is placed on element.short (in elements that refer to other zibs, the name is built up like <<ElementName::ReferenceZibName>>, but we only use the part before the double colons)
  • The zib concept description is placed on element.definition
  • The Dutch zib concept name is placed on element.alias

9.3 Miscellaneous

  • As a rule of thumb, info is placed 'as close as possible' to the elements that actually represent the data. For example: when slicing, the texts are placed on the slice content, not the slice itself. Similarly, in concept containers like Observation.component, this info is placed on the .valueXXX elements. This is also true for the zib mappings.
  • Slices get a lowerCamelCased name based on the functional concept name.
  • New elements defined through extensions get a lowerCamelCased name based on the functional concept name.
  • The key for invariants should be:
    • for zibs: zib-[English zib name]-[number], eg. zib-alert-1.
    • for nl-core: nl-core-[English zib name]-[number].
    • for use case specific profiles: [dataset id]-[number], where [dataset id] is preferably the same as its matching ART-DECOR project prefix.
  • Inline examples in profiles are added (only) when the usage of an element in the profile is not trivial.

10 Data type mapping

In most cases, the mapping between ART-DECOR, zib and FHIR datatypes is straightforward, though there are a number of cases which are not as clear-cut. The table below shows how datatypes from the functional models should be mapped to FHIR.

ART-DECOR zib FHIR Remarks
count INT Count or integer Count in FHIR is derived from Quantity. This is appropriate for observations, such as a count of red blood cells in a specimen. Count in FHIR is a Quantity with system set to http://unitsofmeasure.org and code set to 1 (for units). If this is not appropriate, use integer.
boolean BL boolean
blob ED base64Binary
code CD CodeableConcept or coding or code In general, CodeableConcept will be the right choice. See Using Codes in Resources for details.
complex ANY BackboneElement complex is data which is not further defined in DECOR, and thus cannot be translated.
currency - Money Does not have a zib counterpart currently. Theoretically this could be MO
date - date Does not have a zib counterpart currently. Closest counterpart could be TS
datetime TS dateTime
decimal - decimal Does not have a zib counterpart currently. Theoratically this could be REAL
duration - Duration Does not have a zib counterpart currently. Closest counterpart could be PQ
identifier II Identifier
ordinal CO CodeableConcept or coding or code See Using Codes in Resources for details.
string ST string
ratio - Ratio Does not have a zib counterpart currently. Closest counterpart could be RTO
text - string Does not have a zib counterpart currently.
quantity PQ Quantity