A formal computable definition of an operation (on the RESTful interface) or a named query (using the search interaction).
5.5.1 Scope and Usage
The OperationDefinition resource provides a formal computable definition of an operation or a named query.
The OperationDefinition serves two principal purposes:
To allow for automatic determination of system compatibility
To allow for dynamic generation of forms to drive the operations
See below for further information about these, and about how operations and named queries are executed.
5.5.2 Boundaries and Relationships
OperationDefinitions are published to define operations that servers can implement in a common fashion.
The FHIR specification itself describes some (see below), and other organizations (including
IHE, national programs, jurisdictions and vendors) are able to publish additional OperationDefinitions.
OperationDefinition resources are referred to from two different places:
From a CapabilityStatement, to declare what operations a system does or should implement
From another OperationDefinition resource. This allows for a server to describe a limited implementation of a standard operation, or to allow traceability if the server has to rename the operation due to a name clash
OperationDefinitions can be used to define a custom query (kind = query, discussed below) which
functions as a special kind of search. This is different to a SearchParameter because a custom query
may define multiple parameters and can define of complex search behavior beyond what SearchParameter can specify.
It also typically overrides the behavior of the query functionality, while search parameters can only act
as additional filters.
Definition of an operation or a named query + Warning: Name should be usable as an identifier for the module by machine processing applications such as code generation + Rule: A query operation cannot be defined at the instance level + Rule: A query operation requires input parameters to have a search type + Rule: Named queries always have a single output parameter named 'result' of type Bundle
Canonical identifier for this operation definition, represented as an absolute URI (globally unique) + Warning: URL should not contain | or # - these characters make processing canonical references problematic
Parameters for the operation/query + Rule: Either a type must be provided, or parts + Rule: A search type can only be specified for parameters of type string + Rule: A targetProfile can only be specified for parameters of type Reference, Canonical, or a Resource + Rule: SearchParamType can only be specified on in parameters + Rule: Min <= Max
@prefix fhir: <http://hl7.org/fhir/> .
[ a fhir:OperationDefinition;
fhir:nodeRole fhir:treeRoot; # if this is the parser root
# from Resource: .id, .meta, .implicitRules, and .language
# from DomainResource: .text, .contained, .extension, and .modifierExtension
fhir:url[ uri ] ; # 0..1 Canonical identifier for this operation definition, represented as an absolute URI (globally unique)
fhir:identifier ( [ Identifier ] ... ) ; # 0..* Additional identifier for the implementation guide (business identifier)
fhir:version[ string ] ; # 0..1 Business version of the operation definition
# versionAlgorithm[x]: 0..1 How to compare versions. One of these 2
fhir:versionAlgorithm[ a fhir:string ; string ]
fhir:versionAlgorithm[ a fhir:Coding ; Coding ]
fhir:name[ string ] ; # 1..1 IName for this operation definition (computer friendly)
fhir:title[ string ] ; # 0..1 Name for this operation definition (human friendly)
fhir:status[ code ] ; # 1..1 draft | active | retired | unknown
fhir:kind[ code ] ; # 1..1 Ioperation | query
fhir:experimental[ boolean ] ; # 0..1 For testing only - never for real usage
fhir:date[ dateTime ] ; # 0..1 Date last changed
fhir:publisher[ string ] ; # 0..1 Name of the publisher/steward (organization or individual)
fhir:contact ( [ ContactDetail ] ... ) ; # 0..* Contact details for the publisher
fhir:description[ markdown ] ; # 0..1 Natural language description of the operation definition
fhir:useContext ( [ UsageContext ] ... ) ; # 0..* The context that the content is intended to support
fhir:jurisdiction ( [ CodeableConcept ] ... ) ; # 0..* Intended jurisdiction for operation definition (if applicable)
fhir:purpose[ markdown ] ; # 0..1 Why this operation definition is defined
fhir:copyright[ markdown ] ; # 0..1 Use and/or publishing restrictions
fhir:copyrightLabel[ string ] ; # 0..1 Copyright holder and year(s)
fhir:affectsState[ boolean ] ; # 0..1 Whether content is changed by the operation
fhir:synchronicity[ code ] ; # 0..1 synchronous | asynchronous | either
fhir:code[ code ] ; # 1..1 Recommended name for operation in search url
fhir:comment[ markdown ] ; # 0..1 Additional information about use
fhir:base[ canonical(OperationDefinition) ] ; # 0..1 Marks this as a profile of the base
fhir:resource ( [ code ] ... ) ; # 0..* Types this operation applies to
fhir:system[ boolean ] ; # 1..1 Invoke at the system level?
fhir:type[ boolean ] ; # 1..1 Invoke at the type level?
fhir:instance[ boolean ] ; # 1..1 IInvoke on an instance?
fhir:inputProfile[ canonical(StructureDefinition) ] ; # 0..1 Validation information for in parameters
fhir:outputProfile[ canonical(StructureDefinition) ] ; # 0..1 Validation information for out parameters
fhir:parameter( [ # 0..* IParameters for the operation/query
fhir:name[ code ] ; # 1..1 IName in Parameters.parameter.name or in URL
fhir:use[ code ] ; # 1..1 Iin | out
fhir:scope ( [ code ] ... ) ; # 0..* instance | type | system
fhir:min[ unsignedInt ] ; # 1..1 Minimum Cardinality
fhir:max[ string ] ; # 1..1 Maximum Cardinality (a number or *)
fhir:documentation[ markdown ] ; # 0..1 Description of meaning/use
fhir:type[ code ] ; # 0..1 IWhat type this parameter has
fhir:allowedType ( [ code ] ... ) ; # 0..* Allowed sub-type this parameter can have (if type is abstract)
fhir:targetProfile ( [ canonical(StructureDefinition) ] ... ) ; # 0..* IIf type is Reference | canonical, allowed targets. If type is 'Resource', then this constrains the allowed resource types
fhir:searchType[ code ] ; # 0..1 Inumber | date | string | token | reference | composite | quantity | uri | special
fhir:binding[ # 0..1 ValueSet details if this is coded
fhir:strength[ code ] ; # 1..1 required | extensible | preferred | example | descriptive
fhir:valueSet[ canonical(ValueSet) ] ; # 1..1 Source of value set
] ;
fhir:referencedFrom( [ # 0..* References to this parameter
fhir:source[ string ] ; # 1..1 Referencing parameter
fhir:sourceId[ string ] ; # 0..1 Element id of reference
] ... ) ;
fhir:part ( [ See OperationDefinition.parameter ] ... ) ; # 0..* IParts of a nested Parameter
] ... ) ;
fhir:overload( [ # 0..* Define overloaded variants for when generating code
fhir:parameterName ( [ string ] ... ) ; # 0..* Name of parameter to include in overload
fhir:comment[ string ] ; # 0..1 Comments to go on overload
] ... ) ;
]
Definition of an operation or a named query + Warning: Name should be usable as an identifier for the module by machine processing applications such as code generation + Rule: A query operation cannot be defined at the instance level + Rule: A query operation requires input parameters to have a search type + Rule: Named queries always have a single output parameter named 'result' of type Bundle
Canonical identifier for this operation definition, represented as an absolute URI (globally unique) + Warning: URL should not contain | or # - these characters make processing canonical references problematic
Parameters for the operation/query + Rule: Either a type must be provided, or parts + Rule: A search type can only be specified for parameters of type string + Rule: A targetProfile can only be specified for parameters of type Reference, Canonical, or a Resource + Rule: SearchParamType can only be specified on in parameters + Rule: Min <= Max
@prefix fhir: <http://hl7.org/fhir/> .
[ a fhir:OperationDefinition;
fhir:nodeRole fhir:treeRoot; # if this is the parser root
# from Resource: .id, .meta, .implicitRules, and .language
# from DomainResource: .text, .contained, .extension, and .modifierExtension
fhir:url[ uri ] ; # 0..1 Canonical identifier for this operation definition, represented as an absolute URI (globally unique)
fhir:identifier ( [ Identifier ] ... ) ; # 0..* Additional identifier for the implementation guide (business identifier)
fhir:version[ string ] ; # 0..1 Business version of the operation definition
# versionAlgorithm[x]: 0..1 How to compare versions. One of these 2
fhir:versionAlgorithm[ a fhir:string ; string ]
fhir:versionAlgorithm[ a fhir:Coding ; Coding ]
fhir:name[ string ] ; # 1..1 IName for this operation definition (computer friendly)
fhir:title[ string ] ; # 0..1 Name for this operation definition (human friendly)
fhir:status[ code ] ; # 1..1 draft | active | retired | unknown
fhir:kind[ code ] ; # 1..1 Ioperation | query
fhir:experimental[ boolean ] ; # 0..1 For testing only - never for real usage
fhir:date[ dateTime ] ; # 0..1 Date last changed
fhir:publisher[ string ] ; # 0..1 Name of the publisher/steward (organization or individual)
fhir:contact ( [ ContactDetail ] ... ) ; # 0..* Contact details for the publisher
fhir:description[ markdown ] ; # 0..1 Natural language description of the operation definition
fhir:useContext ( [ UsageContext ] ... ) ; # 0..* The context that the content is intended to support
fhir:jurisdiction ( [ CodeableConcept ] ... ) ; # 0..* Intended jurisdiction for operation definition (if applicable)
fhir:purpose[ markdown ] ; # 0..1 Why this operation definition is defined
fhir:copyright[ markdown ] ; # 0..1 Use and/or publishing restrictions
fhir:copyrightLabel[ string ] ; # 0..1 Copyright holder and year(s)
fhir:affectsState[ boolean ] ; # 0..1 Whether content is changed by the operation
fhir:synchronicity[ code ] ; # 0..1 synchronous | asynchronous | either
fhir:code[ code ] ; # 1..1 Recommended name for operation in search url
fhir:comment[ markdown ] ; # 0..1 Additional information about use
fhir:base[ canonical(OperationDefinition) ] ; # 0..1 Marks this as a profile of the base
fhir:resource ( [ code ] ... ) ; # 0..* Types this operation applies to
fhir:system[ boolean ] ; # 1..1 Invoke at the system level?
fhir:type[ boolean ] ; # 1..1 Invoke at the type level?
fhir:instance[ boolean ] ; # 1..1 IInvoke on an instance?
fhir:inputProfile[ canonical(StructureDefinition) ] ; # 0..1 Validation information for in parameters
fhir:outputProfile[ canonical(StructureDefinition) ] ; # 0..1 Validation information for out parameters
fhir:parameter( [ # 0..* IParameters for the operation/query
fhir:name[ code ] ; # 1..1 IName in Parameters.parameter.name or in URL
fhir:use[ code ] ; # 1..1 Iin | out
fhir:scope ( [ code ] ... ) ; # 0..* instance | type | system
fhir:min[ unsignedInt ] ; # 1..1 Minimum Cardinality
fhir:max[ string ] ; # 1..1 Maximum Cardinality (a number or *)
fhir:documentation[ markdown ] ; # 0..1 Description of meaning/use
fhir:type[ code ] ; # 0..1 IWhat type this parameter has
fhir:allowedType ( [ code ] ... ) ; # 0..* Allowed sub-type this parameter can have (if type is abstract)
fhir:targetProfile ( [ canonical(StructureDefinition) ] ... ) ; # 0..* IIf type is Reference | canonical, allowed targets. If type is 'Resource', then this constrains the allowed resource types
fhir:searchType[ code ] ; # 0..1 Inumber | date | string | token | reference | composite | quantity | uri | special
fhir:binding[ # 0..1 ValueSet details if this is coded
fhir:strength[ code ] ; # 1..1 required | extensible | preferred | example | descriptive
fhir:valueSet[ canonical(ValueSet) ] ; # 1..1 Source of value set
] ;
fhir:referencedFrom( [ # 0..* References to this parameter
fhir:source[ string ] ; # 1..1 Referencing parameter
fhir:sourceId[ string ] ; # 0..1 Element id of reference
] ... ) ;
fhir:part ( [ See OperationDefinition.parameter ] ... ) ; # 0..* IParts of a nested Parameter
] ... ) ;
fhir:overload( [ # 0..* Define overloaded variants for when generating code
fhir:parameterName ( [ string ] ... ) ; # 0..* Name of parameter to include in overload
fhir:comment[ string ] ; # 0..1 Comments to go on overload
] ... ) ;
]
OperationDefinitions can describe entirely new operations, but they can also describe a restricted implementation
of an existing operation e.g. when a server implements some but not all the features of an operation defined in
another specification. These are called derived operation definitions.
An OperationDefinition does by declaring a base as shown in the example:
When constraining an existing operation like this, operation definitions can make
optional parameters required or not used, introduce new parameters (required or optional),
clarify documentation, and even change the code for the operation (see next section).
The derived operation can't change the nature of the operation itself, nor can
it change add types to parameters or prohibit mandatory parameters.
5.5.4.4 OperationDefinition Code
Operations are invoked by their code, not their name. The name is descriptive, for code generation,
e.g. ValueSetExpansion, while the code is what is used in a URL e.g.
http://example.org/fhir/ValueSet/$expand. When defining operations,
for maximum compatibility, use only lowercase ASCII characters.
See Naming Rules & Guidelines
for the internal HL7 rules around codes, which are useful additional advice for all implementers.
It is possible for two different organizations to create different operation definitions with the same code or, perhaps more likely, to define equivalent operations that have the
same code but incompatible approaches in their parameter lists. Note that HL7 will never define multiple operations with the same code.
It is also possible, though unlikely, that a server will be required to support both of
these operations. If this is the case, the server is able to do this by giving one of them
a new code and referring to it by definition in the capability statement. To illustrate
this, assume that two different organizations, "orgA" and "orgB", both define an operation
with a code dothis, and the definitions are incompatible. OrgA publishes its operation
definition at http://orga.com/fhir/dothis.xml, and OrgB publishes its operation at
http://fhir.orgb.com/meta/OperationDefinition/dothis. The server is able to implement
both. Its capability statement will say:
If a general purpose cross server client is looking for the implementation of the
http://fhir.orgb.com/meta/OperationDefinition/dothis operation and wants to be
robust against this name clash problem, instead of simply executing the $dothis
operation, it can look at the server's CapabilityStatement for the underlying
definition URI and then execute with the name given in the capability statement.
Note to implementers: it would be more consistent if CapabilityStatement.rest.operation.name was
actually called "code", since it relates to OperationDefinition.code, but the confusion this
can cause wasn't appreciated until the resource was normative.
5.5.4.5 Describing Operation Parameters
There are 2 ways to describe the input and output parameters for
an operation:
Using OperationDefinition.parameter to describe the parameters
Using OperationDefinition.inputProfile and OperationDefinition.outputProfile
The parameters is a simple list of possible parameters, along with cardinalities and types.
The profiles allow a rich set of validation rules etc. to be provided. OperationDefinitions SHALL
always define the parameters using OperationDefinition.parameter in the resource,
and MAY also provide profiles for the parameters. If present, the profiles SHALL NOT disagree
with the parameters defined for the operation.
As an example, consider an operation that defines 3 parameters, 2 in and 1 out:
This profile would describe a parameters resource with 2 parameters (using slicing), with the same details as the table above.
The operation definition would still list the parameters directly to save applications consuming the definition (e.g. to produce
an OpenAPI document ) from parsing and interpreting the profile.
5.5.4.6 Executing Operations
OperationDefinitions with kind = operation are executed as defined in the Operations Framework.
5.5.4.7 Executing Named Queries
Named queries (OperationDefinitions with kind = query) are executed by performing a search
with the value of the search parameter "_query" set to the name provided in the definition.
Named queries are a kind of search: both client and server must conform to all the requirements of search,
including regarding the content of the result bundle. From a client's perspective, it's really just a kind
of search, though it may have a completely separate processing pipeline.
Named queries cannot be invoked using the $[operationname] mechanism.
If the named query is to be performed over the RESTful API, all the parameters must be simple search parameters,
so that they can be represented directly in the URL without tricky encoding issues. Named queries
always have a single output parameter named "result" of type Bundle.
The order of parameters doesn't matter; a _query parameter anywhere in the query means the entire query will be handled
according to the named query OperationDefinition. Parameters may repeat if permitted by the OperationDefinition
(or for unlisted common search parameters, as specified in this specification).
For named queries, all the standard search parameters are automatically in scope. Specifically, all common search parameters
(e.g. _id, _text, _count, _sort, etc.) as well as search parameters that pertain to the resources
returned by the operation (e.g. name for Patient or Organization) are allowed. "In scope" doesn't
mean all servers will support them. If a server wishes to declare which search parameters it supports
for a given named query, it must explicitly list these in its OperationDefinition (which might be a
server-specific derived OperationDefinition).
5.5.4.8 Passing Resources to Operations
There are two ways to pass resources to an operation: directly or by reference.
The definition of an operation distinguishes between these two, since they have very different behaviors and consequences.
As an example, take the ValueSet.$expand operation.
This operation takes a valueset as a direct parameter. The type of the parameter is
defined as 'ValueSet'. In a Parameters resource, it would be represented like this:
Other parameters are passed by reference. For example, the ChargeItemDefinition.$apply operation
takes two parameters of type Reference - one to the chargeItem and the other to the account. The type of the
parameters is Reference(Charge) and Reference(Account), respectively. The expectation is that the server performing the
operation will resolve those references as part of the operation execution.
In a parameters resource, the chargeItem parameter would be represented like this:
Some operations can take either form; in that case, two distinct parameters
must be defined: one for a resource as a direct parameter, and one for a reference.
5.5.4.9 Determining System Compatibility
A client can determine the compatibility of the server by processing its capability
statement and ensuring that the server implements the specific operation definitions and parameters required by the client. The client can then report a useful error to the user rather than allowing mystifying operational errors to occur.
However, there are fundamental limitations to this approach because
there are many aspects of these operations that are not (or cannot be) defined
in a formal fashion using OperationDefinition, for example, co-occurrence constraints among parameters.
In the same sense, a 3rd party tool can examine a server's CapabilityStatement and a client's definition of an acceptable server to determine whether
those two system are interoperable or not.
5.5.4.10 Dynamically Generating Forms
Finally, it is possible to generate user interface forms automatically from
the OperationDefinition. The documentation in the OperationDefinition.description
and OperationDefinition.parameter.documentation should be sufficient to allow
moderately technical users to guess at the correct content of the form.
For this reason, highly technical documentation should go in OperationDefinition.comment.
It is anticipated that this would be used to automate development processes, rather than to generate end-user forms: such users will usually need more support than can be offered in a generated form.
5.5.4.11 Operations defined as part of this Specification