When adding a new Input Parameter to a Task
profile, you are essentially adding a new slice 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, you
might have 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. Our 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 our dicProcess
.
Let us start out by adding a slice to task-start-dic-process.xml
. Since there is already a slicing defined
on Task.input
by task-start-dic-process.xml
's baseDefinition
, we have to check out this resource 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
We will only need to take a look at the discrimitator
tag for now.
Discriminators define the elements a FHIR processor needs to distinguish slices by. In our 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.
You can learn more about discriminators here.
Let us 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>
Unnecessary elements for this guide are hidden by ... placeholders.
We have now defined a slice on Task.input
with the name and id of example-input
and cardinality of 1..1
. You might
want a different cardinality for your use case. We recommend you 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, we need to define the binding for Task.input:example-input.type
. Because Task.input.type
is a CodeableConcept
which uses codings from a ValueSet,
the discriminator requires us to use 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>
As you can see, we referenced a ValueSet in this binding. When adding an actual slice for your use case, you will have to reference 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, we will make Task.input.coding
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>
In the beginning we mentioned how Task.input.type.coding.system
and Task.input.type.coding.code
have to use fixed values. Here is how we accomplish this:
<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 that we also made the two elements mandatory because they are required by the discriminator.
For the type.coding.system
element we referenced a CodeSystem.
The type.coding.code
element uses a code from this CodeSystem called example-input
.
This is the mechanism by which you actually "name" your Input Parameter. The
type.coding.code
value will identify your Input Parameter when you use
it 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>
When adding an actual slice for your use case, you will also need 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 you will submit using your Input Parameter. You can make it
any of these data types. This is because Type.input.value[x]
refers to *
instead of any particular type in its definition. Let us define it as 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>
Now we have a new Input Parameter of type example-input
which accepts any integer
as its value.