Getting Started: Custom Resources
Guide on work with custom resources
34 cells · updated Jul 17, 2023
Defining a Custom Resource
Sometimes your data does not fit any existing FHIR resources. It is not always obvious that your data cannot be translated to FHIR because of some FHIR generalizations. The right first step is to go to FHIR comunity chat and ask your specific question about mapping to FHIR, or contact Health Samurai modeling team about your concern. If you are still sure that there is no appropriate resource in FHIR or it takes too much time to wait for it, you can define your own Custom Resources in Aidbox.
Custom resources in Aidbox
This Notebook explains Custom Resources using Entity, but since 2303 we recommend to use Aidbox Projects way.
Unfortunatelly, Aidbox Project configuration is not available in Aidbox Sandbox.
Custom resources using Entity
Custom Resources are defined exactly the same way as core FHIR resources. They can refer to existing resources, have uniform REST API for CRUD and Search,and participate in transactions.
Let's imagine that in our application we want to store user preferences such as UI configuration or personalized Patient List filters. It is expected that you have already created a box in Aidbox Sandbox. First of all, we have to define a new resource type by creating an Entity resource.
POST /Entity
content-type: text/yaml
id: UserSetting
type: resource
isOpen: truetype: resource
isOpen: true
id: UserSetting
resourceType: Entity
meta: {lastUpdated: '2021-09-24T11:20:10.327424Z', createdAt: '2021-09-24T11:20:10.327424Z', versionId: '3218'}
GET /UserSetting
accept: text/yamlquery-time: 4
meta: {versionId: '3234'}
type: searchset
resourceType: Bundle
total: 0
link:
- {relation: first, url: '/UserSetting?page=1'}
- {relation: self, url: '/UserSetting?page=1'}
query-timeout: 60000
entry: []
query-sql: ['SELECT "usersetting".* FROM "usersetting" LIMIT ? OFFSET ? ', 100, 0]
SELECT * FROM "usersetting";POST /UserSetting
content-type: text/yaml
id: user-1
theme: darktheme: dark
id: user-1
resourceType: UserSetting
meta: {lastUpdated: '2021-09-24T11:25:38.184205Z', createdAt: '2021-09-24T11:25:38.184205Z', versionId: '3243'}
GET /UserSetting
accept: text/yamlquery-time: 1
meta: {versionId: '3246'}
type: searchset
resourceType: Bundle
total: 1
link:
- {relation: first, url: '/UserSetting?page=1'}
- {relation: self, url: '/UserSetting?page=1'}
query-timeout: 60000
entry:
- resource:
theme: dark
id: user-1
resourceType: UserSetting
meta: {lastUpdated: '2021-09-24T11:25:38.184205Z', createdAt: '2021-09-24T11:25:38.184205Z', versionId: '3243'}
fullUrl: http://localhost:8765/UserSetting/user-1
link:
- {relation: self, url: 'http://localhost:8765/UserSetting/user-1'}
query-sql: ['SELECT "usersetting".* FROM "usersetting" LIMIT ? OFFSET ? ', 100, 0]
SELECT id, resource->>'theme' as theme FROM "usersetting";GET /UserSetting/user-1
accept: text/yamltheme: dark
id: user-1
resourceType: UserSetting
meta: {lastUpdated: '2021-09-24T11:25:38.184205Z', createdAt: '2021-09-24T11:25:38.184205Z', versionId: '3243'}
PUT /UserSetting/user-1
content-type: text/yaml
theme: white
patientsFilters:
- location: ICUtheme: white
patientsFilters:
- {location: ICU}
id: user-1
resourceType: UserSetting
meta: {lastUpdated: '2021-09-24T11:28:19.313003Z', createdAt: '2021-09-24T11:25:38.184205Z', versionId: '3256'}
GET /UserSetting/user-1/_history
accept: text/yamlresourceType: Bundle
type: history
total: 2
entry:
- resource:
theme: white
patientsFilters:
- {location: ICU}
id: user-1
resourceType: UserSetting
meta: {lastUpdated: '2021-09-24T11:28:19.313003Z', createdAt: '2021-09-24T11:25:38.184205Z', versionId: '3256'}
request: {method: PUT, url: UserSetting}
- resource:
theme: dark
id: user-1
resourceType: UserSetting
meta: {lastUpdated: '2021-09-24T11:25:38.184205Z', createdAt: '2021-09-24T11:25:38.184205Z', versionId: '3243'}
request: {method: POST, url: UserSetting}
id: '3256'
query-sql: ['WITH history AS ((SELECT id, txid, ts, resource_type, status::text AS status, resource, cts FROM "usersetting" WHERE id = ?) UNION (SELECT id, txid, ts, resource_type, status::text AS status, resource, cts FROM "usersetting_history" WHERE id = ?)) SELECT * FROM history ORDER BY txid DESC LIMIT ?', user-1, user-1, 100]
DELETE /UserSetting/user-1
accept: text/yamltheme: white
patientsFilters:
- {location: ICU}
id: user-1
resourceType: UserSetting
meta: {lastUpdated: '2021-09-24T11:29:04.192158Z', createdAt: '2021-09-24T11:29:04.192158Z', versionId: '3260'}
POST /UserSetting
content-type: text/yaml
id: user-2
theme:
- name: white
- name: blacktheme:
- {name: white}
- {name: black}
id: user-2
resourceType: UserSetting
meta: {lastUpdated: '2021-09-24T11:31:04.161350Z', createdAt: '2021-09-24T11:31:04.161350Z', versionId: '3268'}
POST /Attribute
content-type: text/yaml
id: UserSetting.theme
path: ['theme']
type: {id: string, resourceType: Entity}
enum: ['dark', 'white']
resource: {id: UserSetting, resourceType: Entity}enum: [dark, white]
path: [theme]
type: {id: string, resourceType: Entity}
resource: {id: UserSetting, resourceType: Entity}
id: UserSetting.theme
resourceType: Attribute
meta: {lastUpdated: '2021-09-24T11:34:39.693486Z', createdAt: '2021-09-24T11:34:39.693486Z', versionId: '3277'}
GET /$json-schema?path=definitions.UserSetting
accept: text/yamlpath: [definitions, UserSetting]
schema:
type: object
patternProperties:
^(_.*|fhir_.*): {}
properties:
id: {type: string}
extension:
type: array
items: {$ref: '#/definitions/Extension'}
modifierExtension:
type: array
items: {$ref: '#/definitions/Extension'}
meta: {$ref: '#/definitions/Meta'}
resourceType: {type: string, constant: UserSetting}
theme:
type: string
enum: [dark, white]
POST /UserSetting
content-type: text/yaml
id: user-3
theme: 2resourceType: OperationOutcome
text: {status: generated, div: Invalid resource}
issue:
- severity: fatal
code: invalid
expression: [UserSetting.theme]
diagnostics: expected type of string
- severity: fatal
code: invalid
expression: [UserSetting.theme]
diagnostics: expected one of dark, white
PATCH /Entity/UserSetting?_type=json-merge-patch
content-type: text/yaml
isOpen: falsetype: resource
isOpen: false
id: UserSetting
resourceType: Entity
meta: {lastUpdated: '2021-09-24T11:43:46.904897Z', createdAt: '2021-09-24T11:20:10.327424Z', versionId: '3307'}
GET /$json-schema?path=definitions.UserSetting
accept: text/yamlpath: [definitions, UserSetting]
schema:
type: object
patternProperties:
^(_.*|fhir_.*): {}
properties:
id: {type: string}
extension:
type: array
items: {$ref: '#/definitions/Extension'}
modifierExtension:
type: array
items: {$ref: '#/definitions/Extension'}
meta: {$ref: '#/definitions/Meta'}
resourceType: {type: string, constant: UserSetting}
theme:
type: string
enum: [dark, white]
additionalProperties: false
And we see the schema keyword additionalProperties: false (last line in the response above)
which means that now our schema is closed.
Let's test it by the request with additional property menu:
POST /UserSetting
content-type: text/yaml
theme: dark
menu: collapsedresourceType: OperationOutcome
text: {status: generated, div: Invalid resource}
issue:
- severity: fatal
code: invalid
expression: [UserSetting.menu]
diagnostics: extra property