First-Class Extensions
In Aidbox there are two ways to define first-class extensions:
Using Zen profiles
Using Attribute
First-class extension as Zen profile
While FHIR uses two different ways to define core elements and extensions, zen profiles provide unified framework to describe both. Zen FHIR format offers user-defined elements or "first-class extensions". In zen profiles, you can define new attributes (elements) for existing (FHIR) resources. The example below shows how to define extensions in zen profiles.
resourceType: Patient
id: sample-pt
extension:
- url: http://hl7.org/fhir/us/core/StructureDefinition/us-core-race
extension:
- url: text
valueString: Asian Indian
- url: ombCategory
valueCoding:
system: urn:oid:2.16.840.1.113883.6.238
code: 2028-9
display: Asian
- url: detailed
valueCoding:
system:
code: 2029-7
display: Asian Indian
Steps to define first-class extension as zen profile:
Initialize zen project and add additional IGs if necessary.
Define your custom first-class extension. For syntax and more examples refer to this page.
{ns my-zen-project import #{zen.fhir hl7-fhir-r4-core.string hl7-fhir-r4-core.dateTime hl7-fhir-r4-core.uri} MyPatient {:zen/tags #{zen/schema zen.fhir/profile-schema} :zen/desc "Patient resource schema with first-class extension definition examples" :zen.fhir/version "0.5.20" :confirms #{zen.fhir/Resource} :zen.fhir/type "Patient" :zen.fhir/profileUri "urn:profile:MyPatientProfile" :type zen/map :keys {:meta {:type zen/map :keys {:tenant-id {:confirms #{hl7-fhir-r4-core.string/schema} :zen/desc "Patient.meta.tenant-id first-class extension" :fhir/extensionUri "http://tenant-id-extension-url"}}} :form {:type zen/vector :zen/desc "Patient.form.[*] array first-class extension" :every {:confirms #{hl7-fhir-r4-core.uri/schema} :fhir/extensionUri "http://patient-form-url"}} :info {:type zen/map :zen/desc "Patient.info nested first-class extension" :fhir/extensionUri "http://patient-info" :keys {:registration {:confirms #{hl7-fhir-r4-core.dateTime/schema} :zen/desc "Patient.info.registration extension.url deduced from key"} :referral {:confirms #{hl7-fhir-r4-core.uri/schema} :fhir/extensionUri "http://patient-info-referral" :zen/desc "Patient.info.referral extension.url is specified"}}}}}
Fix
:zen.fhir/version
errors if neededIn order to fix this error, provide IG bundle with the matching zen FHIR version.
Error message example:
Expected '0.5.8', got '0.4.9' path: [:zen.fhir/version]
Define
:fhir/extensionUri
property value.:fhir/extensionUri
"http://tenant-id-extension-url" is an equivalent of theextensionUrl
field of the Attribute resource and used to form FHIR extension.Replace plain zen type by FHIR type in your extensions. I.e. use
:confirms #{hl7-fhir-r4-core.string/schema}
instead of:type zen/string
.
Define new extension with Attribute
In Aidbox, you can define first-class extensions using the custom resource Attribute.
Let's create an extension definition of type Reference
in the REST Console of Aidbox:
PUT /Attribute/ServiceRequest.requestedOrganizationDepartment
description: Department in the organization that made the service request
resource: {id: ServiceRequest, resourceType: Entity}
path: [requestedOrganizationDepartment]
type: {id: Reference, resourceType: Entity}
refers:
- Organization
extensionUrl: urn:extension:requestedOrganizationDepartment
description
- string.Attribute text description
resource
- required, Reference(Entity).Reference to a target resource type
path
- required, array of strings.Path to a new attribute location in the target resource type
type
- Reference(Entity).Type of data stored in this attribute. Can be any primitive or complex type.
If omitted, treated as
BackboneElement
, i.e. a complex-type object with structure defined via other Attributes relying on this attribute in theirpath
isCollection
- boolean.Whether the attribute is a collection, i.e. if
true
sets attribute cardinality to..*
isRequired
- boolean.Whether the attribute is required, i.e. if
true
sets attribute cardinality to1..
isUnique
- boolean. Sets unique restriction on the attribute.refers
- Reference(Entity).Only for type=Reference. Specifies to which resourceTypes this reference can refer to
extensionUrl
- string.URL which will be used to create
extension
element in FHIR format. If omitted, Attribute won't be transformed in FHIR format
Use your extension
Now, you can create the ServiceRequest
resource using the new attribute requestedOrganizationDepartment
in the root of the resource:
PUT /ServiceRequest/servicerequest-with-aidbox-native-extensions
requestedOrganizationDepartment:
resourceType: Organization
display: City Hospital Neurology Department
identifier: {system: 'urn:oid:1.2.3.4.5.6.7.8', value: '456'}
category:
- coding:
- {code: '183829003',
system: 'http://snomed.info/sct',
display: "Refer for imaging"}
authoredOn: '2020-01-18T15:08:00'
resourceType: ServiceRequest
requester:
resourceType: PractitionerRole
display: Din Morgan
identifier: {value: "1760", system: 'urn:oid:1.2.3.4.5.6.7.6'}
priority: routine
status: active
intent: original-order
performer:
- resourceType: Organization
display: Aga Khan University Hospital Laboratory
identifier: {value: "1514", system: 'urn:oid:1.2.3.4.5.6.7.8'}
subject:
resourceType: Patient
display: Jack Black, 10.12.1941
identifier: {value: '2155800871000065', system: 'urn:oid:1.2.3.4.5.6.7.9'}
FHIR Format
You can get the resource in the FHIR format where our new attribute is rendered as the extension
element:
Note that the URL is different:GET /fhir/ServiceRequest/
GET /fhir/ServiceRequest/servicerequest-with-aidbox-native-extensions
Other extension examples
Let's create an extension of type Reference
and list allowed resource types (Organization in that case) in the refers
property.
PUT /Attribute/ServiceRequest.managingOrganization
resourceType: Attribute
description: Organization that made the service request
resource: {id: ServiceRequest, resourceType: Entity}
path: [managingOrganization]
id: ServiceRequest.managingOrganization
type: {id: Reference, resourceType: Entity}
refers:
- Organization
extensionUrl: urn:extension:requestedOrganization
Extension of type Coding:
PUT /Attribute/ServiceRequest.paymentType
resourceType: Attribute
description: Payment type for the service request, e.g. government health insurance
id: ServiceRequest.paymentType
resource:
id: ServiceRequest
resourceType: Entity
path:
- paymentType
type:
id: Coding
resourceType: Entity
extensionUrl: urn:extension:paymentType
PUT /ServiceRequest/servicerequest-with-aidbox-native-extensions
managingOrganization:
resourceType: Organization
display: City Hospital
identifier: {value: "123", system: 'urn:oid:1.2.3.4.5.6.7.8'}
requestedOrganizationDepartment:
resourceType: Organization
display: City Hospital Neurology Department
identifier: {system: 'urn:oid:1.2.3.4.5.6.7.8', value: '456'}
paymentType: {system: 'urn:CodeSystem:paymentType',
code: "1",
display: "Government Health Insurance"}
resourceType: ServiceRequest
status: active
intent: original-order
subject:
resourceType: Patient
display: Jack Black, 10.12.1941
identifier: {value: '2155800871000065', system: 'urn:oid:1.2.3.4.5.6.7.9'}
GET /fhir/ServiceRequest/servicerequest-with-aidbox-native-extensions
Nested extensions
Let's create a structure of nested attributes:
PUT /Attribute/ServiceRequest.performerInfo
resourceType: Attribute
description: Information filled in by performer
resource: {id: ServiceRequest, resourceType: Entity}
path: [performerInfo]
id: ServiceRequest.performerInfo
extensionUrl: urn:extension:performerInfo
PUT /Attribute/ServiceRequest.performerInfo.performedBy
resourceType: Attribute
description: 'Information filled in by performer: performed by ["Practitioner" "PractitionerRole" "Organization" "CareTeam" "HealthcareService" "Patient" "Device" "RelatedPerson"]'
resource: {id: ServiceRequest, resourceType: Entity}
path: [performerInfo, performedBy]
id: ServiceRequest.performerInfo.performedBy
type: {id: Reference, resourceType: Entity}
isCollection: true
refers:
- Practitioner
- PractitionerRole
- Organization
- CareTeam
- HealthcareService
- Patient
- Device
- RelatedPerson
extensionUrl: urn:extension:performerInfo.performedBy
PUT /Attribute/ServiceRequest.performerInfo.actualLocationReference
resourceType: Attribute
description: 'Information filled in by performer: actual location reference'
resource: {id: ServiceRequest, resourceType: Entity}
path: [performerInfo, actualLocationReference]
id: ServiceRequest.performerInfo.actualLocationReference
type: {id: Reference, resourceType: Entity}
isCollection: true
refers:
- Location
extensionUrl: urn:extension:performerInfo.actualLocationReference
PUT /Attribute/ServiceRequest.performerInfo.requestStatus
resourceType: Attribute
description: 'Information filled in by performer: request status'
resource: {id: ServiceRequest, resourceType: Entity}
path: [performerInfo, requestStatus]
id: ServiceRequest.performerInfo.requestStatus
type: {id: code, resourceType: Entity}
enum:
- draft
- new
- in-progress
- suspended
- expanded
- completed
- archive
- cancelled
extensionUrl: urn:extension:performerInfo.requestStatus
PUT /Attribute/ServiceRequest.performerInfo.requestActionHistory
resourceType: Attribute
description: 'Information filled in by performer: request action history'
resource: {id: ServiceRequest, resourceType: Entity}
path: [performerInfo, requestActionHistory]
id: ServiceRequest.performerInfo.requestActionHistory
isCollection: true
extensionUrl: urn:extension:performerInfo.requestActionHistory
PUT /Attribute/ServiceRequest.performerInfo.requestActionHistory.action
resourceType: Attribute
description: 'Information filled in by performer: request action history - action'
resource: {id: ServiceRequest, resourceType: Entity}
path: [performerInfo, requestActionHistory, action]
id: ServiceRequest.performerInfo.requestActionHistory.action
type: {id: string, resourceType: Entity}
extensionUrl: urn:extension:performerInfo.requestActionHistory.action
PUT /Attribute/ServiceRequest.performerInfo.requestActionHistory.date
resourceType: Attribute
description: 'Information filled in by performer: request action history - date'
resource: {id: ServiceRequest, resourceType: Entity}
path: [performerInfo, requestActionHistory, date]
id: ServiceRequest.performerInfo.requestActionHistory.date
type: {id: dateTime, resourceType: Entity}
extensionUrl: urn:extension:performerInfo.requestActionHistory.date
PUT /Attribute/ServiceRequest.performerInfo.requestActionHistory.subject
resourceType: Attribute
description: 'Information filled in by performer: request action history - subject'
resource: {id: ServiceRequest, resourceType: Entity}
path: [performerInfo, requestActionHistory, subject]
id: ServiceRequest.performerInfo.requestActionHistory.subject
type: {id: Reference, resourceType: Entity}
extensionUrl: urn:extension:performerInfo.requestActionHistory.subject
PUT /Attribute/ServiceRequest.performerInfo.requestActionHistory.note
resourceType: Attribute
description: 'Information filled in by performer: request action history - note'
resource: {id: ServiceRequest, resourceType: Entity}
path: [performerInfo, requestActionHistory, note]
id: ServiceRequest.performerInfo.requestActionHistory.note
type: {id: string, resourceType: Entity}
extensionUrl: urn:extension:performerInfo.requestActionHistory.note
PUT /Attribute/ServiceRequest.performerInfo.requestActionHistory.author
resourceType: Attribute
description: 'Information filled in by performer: request action history - author'
resource: {id: ServiceRequest, resourceType: Entity}
path: [performerInfo, requestActionHistory, author]
id: ServiceRequest.performerInfo.requestActionHistory.author
type: {id: Reference, resourceType: Entity}
extensionUrl: urn:extension:performerInfo.requestActionHistory.author
Let's add a resource using created extensions:
PUT /ServiceRequest/servicerequest-with-aidbox-native-extensions
resourceType: ServiceRequest
performerInfo:
performedBy:
- resourceType: Organization
display: City Hospital
- resourceType: PractitionerRole
display: Mark Sloan
requestStatus: completed
requestActionHistory:
- date: '2020-01-14T12:15:22'
action: new
author: {display: Meredith Grey (Psychiatrist-narcologist), resourceType: PractitionerRole}
- date: '2020-01-14T12:15:36'
action: in-progress
author: {display: Derek Shepherd (General practitioner), resourceType: PractitionerRole}
- date: '2020-01-14T12:19:00'
action: in-progress
author: {display: Derek Shepherd (General practitioner), resourceType: PractitionerRole}
subject: {display: Mark Sloan (Dental surgeon), resourceType: PractitionerRole}
note: Referred to Dr. Mark Sloan (Dental surgeon)
- date: '2020-01-14T15:05:20'
action: meeting
author: {display: Mark Sloan (Dental surgeon), resourceType: PractitionerRole}
- date: '2020-01-14T15:22:46'
action: completed
author: {display: Mark Sloan (Dental surgeon), resourceType: PractitionerRole}
status: completed
intent: original-order
category:
- text: Telemedicine consultation referral
coding:
- {code: "TMC", system: 'urn:CodeSystem:servicerequest-category', display: "Telemedicine consultation"}
subject:
resourceType: Patient
display: Jack Black, 10.12.1941
identifier: {value: '2155800871000065', system: 'urn:oid:1.2.3.4.5.6.7.9'}
GET /fhir/ServiceRequest/servicerequest-with-aidbox-native-extensions
Using FHIR extensions
FHIR extensions defined in the specification can be found in the registry http://hl7.org/fhir/extensibility-registry.html.
Let's create an attribute for the servicerequest-precondition extension:
PUT /Attribute/ServiceRequest.precondition
resourceType: Attribute
description: "The condition or state of the patient, prior or during
the diagnostic procedure or test, for example, fasting, at-rest,
or post-operative. This captures circumstances that may influence
the measured value and have bearing on the interpretation of the result."
resource: {id: ServiceRequest, resourceType: Entity}
path: [precondition]
id: ServiceRequest.precondition
type: {id: CodeableConcept, resourceType: Entity}
isCollection: true
extensionUrl: "http://hl7.org/fhir/StructureDefinition/servicerequest-precondition"
Let's create a resource in the FHIR format:
PUT /fhir/ServiceRequest/servicerequest-with-aidbox-native-extensions
resourceType: ServiceRequest
status: active
intent: original-order
subject:
type: Patient
display: Jack Black, 10.12.1941
extension:
- url: http://hl7.org/fhir/StructureDefinition/servicerequest-precondition
valueCodeableConcept:
text: After calorie fasting
coding:
- code: "726055006"
system: http://snomed.info/sct
display: After calorie fasting
- url: http://hl7.org/fhir/StructureDefinition/servicerequest-precondition
valueCodeableConcept:
text: At rest
coding:
- code: "263678003"
system: http://snomed.info/sct
display: At rest
Let's get the resource in the Aidbox format:
GET /ServiceRequest/servicerequest-with-aidbox-native-extensions
Create FHIR primitive type extension
FHIR primitive named fieldName can be extended with _fieldName field. Aidbox treats fieldName as independent from fieldName. Aidbox do not validate fields with names started with underscore.
Suppose we need to extend Patient.gender attribute with primitive type. It means, that we need to create Patient._gender attribute.
PUT /Attribute/Patient._gender
path:
- _gender
resource:
id: Patient
resourceType: Entity
id: Patient._gender
resourceType: Attribute
Now we can add extension attribute into _gender attribute.
PUT /Attribute/Patient._gender.extension
path:
- _gender
- extension
resource:
id: Patient
resourceType: Entity
id: Patient._gender.extension
isCollection: true
type:
id: Extension
resourceType: Entity
resourceType: Attribute
Finally, add Patient with extended gender.
PUT /Patient/p-gender
gender: male
_gender:
extension:
- valueCodeableConcept:
coding:
- code: code-male
system: system-gender
url: https://example.com
Last updated
Was this helpful?