Custom resources using StructureDefinition

Custom resources are defined by individual organizations or projects to meet specific needs not covered by the FHIR standard. While these resources can be useful within a particular ecosystem, they may not be interoperable with other systems that do not recognize or support those custom resources.

FHIR uses StructureDefinition resources to model data structures. Aidbox allows you to model data in the same way by expressing your custom resource using a FHIR StructureDefinition resource.

Configure Aidbox

To begin using custom FHIR resources, enable the FHIR Schema validation engine in Aidbox.

Setup Aidbox with FHIR Schema validation engine

Create StructureDefinition for custom resource

To create a custom resource in Aidbox using StructureDefinition you have to create StructureDefinition resource via REST API.

It is a usual FHIR StructureDefinition resource, but with several limitations:

  1. name, type, and id must be equal.

  2. kind: must be equal to resource or logical

  3. derivation: If it is set to specialization - Aidbox will create a new resource type with tables in the database and other resource infrastructure. If it is set to constraint - Aidbox will create a new profile that can be referenced on resource instances.

The further guide details the process of creating custom resources for a notification system, demonstrating the typical workflow of creating, managing, and sending template-based notifications from a healthcare system to patients using custom resources defined through StructureDefinition.

To implement a notification flow, you may need a notification resource and a template resource to store your notification messages.

Let's start with shaping a TutorNotificationTemplate resource.

This resource contains one property defined under StructureDefinition.differential:

  1. template: This property is for notification template text and is of the FHIR string data type. Also, it is a required property.

POST /fhir/StructureDefinition
content-type: application/json
accept: application/json

{
    "derivation": "specialization",
    "name": "TutorNotificationTemplate",
    "abstract": false,
    "type": "TutorNotificationTemplate",
    "status": "active",
    "kind": "resource",
    "url": "http://example.org/StructureDefinition/TutorNotificationTemplate",
    "baseDefinition": "http://hl7.org/fhir/StructureDefinition/DomainResource",
    "differential": {
        "element": [
            {
                "id": "TutorNotificationTemplate",
                "path": "TutorNotificationTemplate",
                "min": 0,
                "max": "*"
            },
            {
                "id": "TutorNotificationTemplate.template",
                "path": "TutorNotificationTemplate.template",
                "min": 1,
                "max": "1",
                "type": [
                    {
                        "code": "string"
                    }
                ]
            }
        ]
    }
}

Now, that we got resource to store our templates, let's shape a more complex one - a resource TutorNotification that has the following properties:

  1. type: property that contains binding value set URL in valueSet property and strength: required, that is used to force binding validation.

  2. status: property with binding to valueSet: http://hl7.org/fhir/ValueSet/task-status with additional constraints to requested, in-progress or completed values.

  3. template: reference to TutorNotificationTemplate that we created above.

  4. message: message text and is of the FHIR string data type.

  5. sendAfter: property that specifies the dateTime after which this notification should be sent.

  6. subject: reference to the Patient resource to whom this notification will be sent.

POST /fhir/StructureDefinition
content-type: application/json
accept: application/json

{
  "url": "http://example.com/aidbox-sms-tutor/TutorNotification",
  "name": "TutorNotification",
  "status": "active",
  "kind": "resource",
  "abstract": false,
  "type": "TutorNotification",
  "baseDefinition": "http://hl7.org/fhir/StructureDefinition/DomainResource",
  "derivation": "specialization",
  "differential": {
    "element": [
      {
        "id": "TutorNotification",
        "path": "TutorNotification",
        "min": 0,
        "max": "*"
      },
      {
        "id": "TutorNotification.type",
        "path": "TutorNotification.type",
        "min": 1,
        "max": "1",
        "type": [
          {
            "code": "string"
          }
        ],
        "binding": {
          "strength": "required",
          "valueSet": "http://hl7.org/fhir/ValueSet/contact-point-system"
        }
      },
      {
        "id": "TutorNotification.status",
        "path": "TutorNotification.status",
        "min": 1,
        "max": "1",
        "type": [
          {
            "code": "string"
          }
        ],
        "constraint": [
          {
            "key": "cont-status",
            "severity": "error",
            "human": "Status should be 'requested', 'in-progress' or 'completed'",
            "expression": "%context='requested' or %context='in-progress' or %context='completed'"
          }
        ],
        "binding": {
          "strength": "required",
          "valueSet": "http://hl7.org/fhir/ValueSet/task-status"
        }
      },
      {
        "id": "TutorNotification.template",
        "path": "TutorNotification.template",
        "min": 1,
        "max": "1",
        "type": [
          {
            "code": "Reference",
            "targetProfile": [
              "http://example.com/aidbox-sms-tutor/TutorNotificationTemplate"
            ]
          }
        ]
      },
      {
        "id": "TutorNotification.message",
        "path": "TutorNotification.message",
        "min": 0,
        "max": "1",
        "type": [
          {
            "code": "string"
          }
        ]
      },
      {
        "id": "TutorNotification.sendAfter",
        "path": "TutorNotification.sendAfter",
        "min": 1,
        "max": "1",
        "type": [
          {
            "code": "dateTime"
          }
        ]
      },
      {
        "id": "TutorNotification.subject",
        "path": "TutorNotification.subject",
        "min": 1,
        "max": "1",
        "type": [
          {
            "code": "Reference",
            "targetProfile": [
              "http://hl7.org/fhir/StructureDefinition/Patient"
            ]
          }
        ]
      }
    ]
  }
}

Define search parameters

POST /fhir/TutorNotification
content-type: application/json
accept: application/json

{
  "resourceType": "TutorNotification",
  "type": "sms",
  "status": "requested",
  "template": {
    "reference": "TutorNotificationTemplate/welcome"
  },
  "sendAfter": "2024-07-12T12:00:00.000Z",
  "subject": {
    "reference": "Patient/pt-1"
  }
}

So request that creates a welcome sms notification for James Morgan at 12:00 should look like this:

POST /fhir/Patient
content-type: application/json
accept: application/json

{
  "id": "pt-1",
  "name": [
    {
      "given": [
        "James"
      ],
      "family": "Morgan"
    }
  ],
  "resourceType": "Patient"
}

Then we probably want to create some patient:

POST /fhir/TutorNotificationTemplate
content-type: application/json
accept: application/json

{
  "id": "welcome",
  "resourceType": "TutorNotificationTemplate",
  "template": "Hello user name: {{patient.name.given}}\n"
}

Let's create an instance of TutorNotificationTemplate resource with a welcome message based on the related patient's given name.

Now you can interact with cuctom resources just like with any other FHIR resources.

Interact with a resource

GET /fhir/TutorNotification?_include=TutorNotification:subject:Patient

It allows you to make the following requests:

POST /fhir/SearchParameter
content-type: application/json
accept: application/json

{
  "resourceType": "SearchParameter",
  "id": "TutorNotification-subject",
  "url": "http://example.com/aidbox-sms-tutor/TutorNotification-subject",
  "version": "0.0.1",
  "status": "draft",
  "name": "subject",
  "code": "subject",
  "base": [
    "TutorNotification"
  ],
  "type": "reference",
  "description": "Search TutorNotification by subject",
  "expression": "TutorNotification.subject"
}

The other one is used to include related Patient resources in the search bundle.

GET /fhir/TutorNotification?status=requested