Adding Task Input Parameters to Task Profiles
Adding Task Input Parameters to Task Profiles
When adding a new Input Parameter to a Task profile, a new slice is added to Task.input
. Slicing is part of profiling in FHIR. Profiling lets you create your own FHIR definitions based on pre-existing FHIR definitions. A slicing defines constraints on element lists like Task.input
e.g. by only allowing the elements to be of certain types.
For example, there might be a list of fruits in a FruitBasket
resource. Constraining that list to only include fruits of type Apple
, Banana
and Orange
would be considered slicing.
This guide will not cover how slicing works in general, only for the case presented by the DSF FHIR resource context. The goal will be to add a new Input Parameter of type example-input
to the task-start-dic-process.xml
profile which will be used to submit integer
values to a process called dicProcess
.
As a first step, a slice to task-start-dic-process.xml
is added. Since there is already a slicing defined on Task.input
by task-start-dic-process.xml
's baseDefinition
, this resource has to be looked at first. As a part of the differential statement, slicing also uses Element Definitions.
The slicing for Task.input
is defined in this part of the baseDefinition
:
<element id="Task.input">
<extension url="http://hl7.org/fhir/StructureDefinition/structuredefinition-explicit-type-name">
<valueString value="Parameter" />
</extension>
<path value="Task.input" />
<slicing>
<discriminator>
<type value="value" />
<path value="type.coding.system" />
</discriminator>
<discriminator>
<type value="value" />
<path value="type.coding.code" />
</discriminator>
<rules value="openAtEnd" />
</slicing>
<min value="1" />
</element>
The resource can be found here
First look at the discriminator
tag. Discriminators define the elements a FHIR processor needs to distinguish slices by. In this case, a processor would look at the values for type.coding.system
and type.coding.code
to determine which slice this element belongs to. The discriminator type value
implies that type.coding.system
and type.coding.code
have to be present in all slices and need to have a fixed value. There is more information about discriminators in the official FHIR documentation.
Now revisit task-start-dic-process.xml
and start adding a slice called example-input
to it:
<StructureDefinition xmlns="http://hl7.org/fhir">
...
<differential>
...
<element id="Task.input:example-input">
<path value="Task.input" />
<sliceName value="example-input" />
<min value="1" />
<max value="1" />
</element>
</differential>
</StructureDefinition>
Irrelevant elements for this guide are hidden by ... placeholders.
There is now a slice defined on Task.input
with the name and id of example-input
and cardinality of 1..1
. The name and cardinality depend on the use case. It is recommended to also take a look at the documentation for ElementDefinition.id and ElementDefinition.path. They explain how to create the proper values for these elements. Cardinality is also part of the element definition hierarchy (see ElementDefinition.min and ElementDefinition.max).
Next up is the binding for Task.input:example-input.type
. Because Task.input.type
is a CodeableConcept
which uses codings from a ValueSet, the discriminator requires the use of required
as the binding strength:
<StructureDefinition xmlns="http://hl7.org/fhir">
...
<differential>
...
<element id="Task.input:example-input">
<path value="Task.input" />
<sliceName value="example-input" />
<min value="1" />
<max value="1" />
</element>
<element id="Task.input:example-input.type">
<path value="Task.input.type" />
<binding>
<strength value="required"/>
<valueSet value="http://dsf.dev/fhir/ValueSet/example" />
</binding>
</element>
</differential>
</StructureDefinition>
The binding now references a ValueSet. Moving beyond this example will require referencing an existing ValueSet resource or create a new one. A guide on how to create them can be found here.
Since the discriminator requires Task.input.coding.code
and Task.input.coding.system
to be present, Task.input.coding
will be marked as mandatory as well:
<StructureDefinition xmlns="http://hl7.org/fhir">
...
<differential>
...
<element id="Task.input:example-input">
<path value="Task.input" />
<sliceName value="example-input" />
<min value="1" />
<max value="1" />
</element>
<element id="Task.input:example-input.type">
<path value="Task.input.type" />
<binding>
<strength value="required"/>
<valueSet value="http://dsf.dev/fhir/ValueSet/example" />
</binding>
</element>
<element id="Task.input:example-input.type.coding">
<path value="Task.input.type.coding"/>
<min value="1" />
</element>
</differential>
</StructureDefinition>
The beginning mentioned how Task.input.type.coding.system
and Task.input.type.coding.code
have to use fixed values. Here is how this is accomplished:
<StructureDefinition xmlns="http://hl7.org/fhir">
...
<differential>
...
<element id="Task.input:example-input">
<path value="Task.input" />
<sliceName value="example-input" />
<min value="1" />
<max value="1" />
</element>
<element id="Task.input:example-input.type">
<path value="Task.input.type" />
<binding>
<strength value="required"/>
<valueSet value="http://dsf.dev/fhir/ValueSet/example" />
</binding>
</element>
<element id="Task.input:example-input.type.coding">
<path value="Task.input.type.coding"/>
<min value="1" />
</element>
<element id="Task.input:example-input.type.coding.system">
<path value="Task.input.type.coding.system"/>
<min value="1"/>
<fixedUri value="http://dsf.dev/fhir/CodeSystem/example"/>
</element>
<element id="Task.input:example-input.type.coding.code">
<path value="Task.input.type.coding.code"/>
<min value="1"/>
<fixedCode value="example-input" />
</element>
</differential>
</StructureDefinition>
Notice the two new elements were marked as mandatory because they are required by the discriminator.
The type.coding.system
element references a CodeSystem. The type.coding.code
element uses a code from this CodeSystem called example-input
. This is the mechanism by which Input Parameter are "named". The type.coding.code
value will identify the Input Parameter when it is used in an actual Task resource. Here is how this would look like:
<Task xmlns="http://hl7.org/fhir">
...
<input>
<type>
<coding>
<system value="http://dsf.dev/fhir/CodeSystem/example"/>
<code value="example-input" />
</coding>
</type>
...
</input>
</Task>
Adding a slice in a different use case will also require to reference an existing CodeSystem resource or create a new one to reference. A guide on how to create them can be found here.
Task.input.value[x]
is the actual value submitted when using the Input Parameter. They may be any of these data types. This is because Type.input.value[x]
refers to *
instead of any particular type in its definition. In this case, let it be an integer
type`:
<StructureDefinition xmlns="http://hl7.org/fhir">
...
<differential>
...
<element id="Task.input:example-input">
<path value="Task.input" />
<sliceName value="example-input" />
<min value="1" />
<max value="1" />
</element>
<element id="Task.input:example-input.type">
<path value="Task.input.type" />
<binding>
<strength value="required"/>
<valueSet value="http://dsf.dev/fhir/ValueSet/example" />
</binding>
</element>
<element id="Task.input:example-input.type.coding">
<path value="Task.input.type.coding"/>
<min value="1" />
</element>
<element id="Task.input:example-input.type.coding.system">
<path value="Task.input.type.coding.system"/>
<min value="1"/>
<fixedUri value="http://dsf.dev/fhir/CodeSystem/example"/>
</element>
<element id="Task.input:example-input.type.coding.code">
<path value="Task.input.type.coding.code"/>
<min value="1"/>
<fixedCode value="example-input" />
</element>
<element id="Task.input:example-input.value[x]">
<path value="Task.input.value[x]"/>
<type>
<code value="integer"/>
</type>
</element>
</differential>
</StructureDefinition>
There is now a new Input Parameter of type example-input
which accepts any integer
as its value.
Related Topics
Creating CodeSystems for DSF processes, Creating ValueSets for DSF processes, Task