Introduction
Overview
This section documents custom FHIR resources developed specifically for the Mona ICU project. These resources extend the standard FHIR specification to address domain-specific requirements that cannot be adequately modeled using core FHIR resources alone.
Custom resources are defined using FHIR Shorthand (FSH), compiled to FHIR JSON via SUSHI, and automatically deployed to Aidbox through a GitLab CI/CD pipeline.
Why Custom Resources?
While FHIR provides a comprehensive set of resources for healthcare data exchange, certain clinical workflows require specialized data structures. Custom resources enable:
- Domain-specific modeling: Capture concepts unique to intensive care workflows
- Simplified data access: Avoid complex workarounds with extensions and contained resources
- Type safety: Define strict validation rules via FHIR constraints
- Searchability: Custom SearchParameters for efficient querying
Example Use Cases
| Custom Resource | Purpose |
|---|---|
| SubEncounter | Temporal subdivision of hospital encounters for phase-specific reporting |
| SubEncounterLink | Versionable associations between SubEncounters and clinical resources |
Development Workflow
The following diagram illustrates the end-to-end workflow for defining, compiling, and deploying custom FHIR resources:
Step-by-Step Process
- Write FSH Definitions in
fsh/input/fsh/directory - Configure SUSHI settings in
sushi-config.yaml - Compile locally using
npm run buildto validate syntax - Commit and push to the Git repository
- Automated deployment via GitLab CI/CD to Aidbox
FHIR Shorthand (FSH)
What is FSH?
FHIR Shorthand (FSH) is a domain-specific language designed for authoring FHIR artifacts. It provides a compact, human-readable syntax that simplifies the creation of:
- StructureDefinitions (profiles, extensions, logical models)
- ValueSets and CodeSystems
- SearchParameters
- Examples
Advantages Over JSON/XML
| Aspect | FSH | FHIR JSON/XML |
|---|---|---|
| Readability | High - concise, declarative syntax | Low - verbose nested structures |
| Maintainability | Easy to diff and review in Git | Difficult to track changes |
| Type safety | Built-in validation rules | Manual constraint validation |
| Learning curve | Moderate - requires FSH knowledge | Low for JSON, but complex FHIR knowledge needed |
Example Comparison
FHIR JSON (verbose):
{
"resourceType": "StructureDefinition",
"id": "SubEncounter",
"url": "http://mona.icu/StructureDefinition/SubEncounter",
"name": "SubEncounter",
"status": "active",
"kind": "resource",
"abstract": false,
"type": "SubEncounter",
"baseDefinition": "http://hl7.org/fhir/StructureDefinition/DomainResource",
"differential": {
"element": [
{
"id": "SubEncounter.encounter",
"path": "SubEncounter.encounter",
"min": 1,
"max": "1",
"type": [{"code": "Reference", "targetProfile": ["http://hl7.org/fhir/StructureDefinition/Encounter"]}]
}
]
}
}
FSH (concise):
Logical: SubEncounter
Id: SubEncounter
* ^url = "http://mona.icu/StructureDefinition/SubEncounter"
* ^status = #active
* encounter 1..1 Reference(Encounter) "Parent Encounter"
SUSHI Compiler
What is SUSHI?
SUSHI ("SUSHI Unshortens SHorthand Inputs") is the reference implementation compiler for FSH. It converts FSH definitions into standard FHIR JSON resources.
Key Features
- Automatic generation of StructureDefinitions, SearchParameters, ValueSets
- Validation of FSH syntax and FHIR conformance
- Dependency management for FHIR packages
- Snapshot generation for profiles
Configuration
SUSHI is configured via sushi-config.yaml:
canonical: http://mona.icu
status: active
version: 1.0.0
fhirVersion: 4.0.1
FSHOnly: true
applyExtensionMetadataToRoot: false
| Setting | Purpose |
|---|---|
canonical | Base URL for all generated resources |
fhirVersion | Target FHIR specification version |
FSHOnly | Skip IG publication (we only need JSON output) |
Running SUSHI
# Install dependencies
npm install
# Compile FSH to FHIR JSON
npm run build
# Output appears in: fsh/fsh-generated/resources/
GitLab CI/CD Pipeline
Pipeline Overview
The GitLab CI/CD pipeline automatically deploys FHIR resources to Aidbox whenever changes are pushed to the repository. The pipeline:
- Installs dependencies (Node.js, SUSHI, HURL)
- Compiles FSH definitions to FHIR JSON
- Uploads all generated resources to the configured Aidbox instance
For the current pipeline implementation, refer to .gitlab-ci.yml in the mona3-fhir-definitions repository. The pipeline configuration may evolve over time.
Pipeline Flow
Upload Mechanism
The pipeline iterates through all generated FHIR JSON files and uploads them to Aidbox using PUT requests (upsert operation). This ensures that resources are created if they don't exist, or updated if they do.
For the current implementation, see the upload-resources.sh script and .gitlab-ci.yml in the mona3-fhir-definitions repository.
The pipeline uses PUT requests to upload resources. This performs an upsert operation (create or update), ensuring idempotency. Resources are never deleted automatically—only created or modified.
Aidbox Deployment
Resource Lifecycle
Important Deployment Rules
| Rule | Explanation |
|---|---|
| Resources are never deleted | Removing a .fsh file does NOT delete the resource from Aidbox |
| Updates are idempotent | Re-deploying the same definition is safe |
| IDs must be stable | Changing a resource's id creates a new resource (orphaning the old one) |
| Manual cleanup required | To remove obsolete resources, use Aidbox UI or API |
Deployment Environments
The pipeline supports deployment to different Aidbox instances via environment variables:
| Variable | Purpose | Example |
|---|---|---|
AIDBOX_URL | Target Aidbox server URL | https://dev.aidbox.app |
AIDBOX_AUTH | Basic auth credentials (base64) | client:secret |
Override during manual pipeline runs:
- Navigate to GitLab → CI/CD → Pipelines → Run Pipeline
- Provide
aidbox_urlandaidbox_authas input parameters
Adding New Custom Resources
Step-by-Step Guide
- Create FSH file in
fsh/input/fsh/:
# Example: Creating a new resource
cd /path/to/mona3-fhir-definitions
touch fsh/input/fsh/MyCustomResource.fsh
- Define the resource using FSH syntax:
Logical: MyCustomResource
Id: MyCustomResource
Title: "My Custom Resource"
Description: "Description of what this resource represents"
* ^url = "http://mona.icu/StructureDefinition/MyCustomResource"
* ^status = #active
* ^kind = #resource
* ^type = "MyCustomResource"
* identifier 0..* Identifier "Business identifier"
* status 1..1 code "active | inactive | entered-in-error"
* subject 1..1 Reference(Patient) "Patient reference"
- Add SearchParameters (if needed):
Instance: mycustomresource-status
InstanceOf: SearchParameter
Usage: #definition
* url = "http://mona.icu/SearchParameter/mycustomresource-status"
* name = "MyCustomResourceStatus"
* status = #active
* description = "Search by status"
* code = #status
* base = #MyCustomResource
* type = #token
* expression = "MyCustomResource.status"
- Compile locally to validate:
npm run build
Check for errors in the terminal output. Generated files appear in fsh/fsh-generated/resources/.
- Review generated JSON:
cat fsh/fsh-generated/resources/StructureDefinition-MyCustomResource.json
- Commit and push:
git add fsh/input/fsh/MyCustomResource.fsh
git commit -m "Add MyCustomResource custom resource"
git push
- Monitor pipeline:
Navigate to GitLab → CI/CD → Pipelines to verify successful deployment.
Local Development Workflow
Prerequisites
- Node.js 20+: Install from nodejs.org
- Git: Version control
- Text editor: VS Code with FSH Language Support extension recommended
Setup
# Clone repository
git clone <repository-url>
cd mona3-fhir-definitions
# Install dependencies
npm install
Development Loop
Testing Changes Locally
You can upload resources manually without triggering the pipeline:
# Set environment variables
export AIDBOX_URL="https://dev.aidbox.app"
export AIDBOX_AUTH="client:secret"
# Upload all resources
npm run upload
# Or upload a single resource manually
curl -X PUT \
-H "Authorization: Basic $(echo -n 'client:secret' | base64)" \
-H "Content-Type: application/json" \
-d @fsh/fsh-generated/resources/StructureDefinition-MyResource.json \
https://dev.aidbox.app/StructureDefinition/MyResource
Best Practices
FSH Authoring
✅ Do:
- Use descriptive resource and element names
- Add comprehensive descriptions to all elements
- Define invariants for business rules
- Group related resources in the same file
❌ Don't:
- Hardcode version numbers in individual resources (use
sushi-config.yaml) - Create overly complex nested structures (consider separate resources instead)
- Forget to define SearchParameters for queryable fields
Version Control
✅ Do:
- Commit FSH source files, not generated JSON
- Write clear commit messages explaining changes
- Use feature branches for major changes
❌ Don't:
- Commit
fsh/fsh-generated/directory (it's in.gitignore) - Make breaking changes to production resources without versioning
Deployment
✅ Do:
- Test FSH compilation locally before pushing
- Monitor pipeline logs for upload errors
- Document custom resources in this documentation site
❌ Don't:
- Push directly to
mainwithout review (use merge requests) - Deploy to production Aidbox without testing in dev/staging first
- Assume deleted FSH files are removed from Aidbox automatically
Troubleshooting
Common Compilation Errors
| Error Message | Cause | Solution |
|---|---|---|
Unrecognized keyword | Invalid FSH syntax | Check FSH specification |
Cardinality mismatch | Element cardinality violates base definition | Adjust min..max values |
Unknown type | Referenced resource type doesn't exist | Verify resource name spelling |
Pipeline Failures
Error: AIDBOX_URL environment variable is not set
Solution: Configure AIDBOX_URL and AIDBOX_AUTH in GitLab CI/CD settings (Settings → CI/CD → Variables)
Error: 401 Unauthorized during upload
Solution: Verify AIDBOX_AUTH credentials are correct and have write permissions
Error: 422 Unprocessable Entity from Aidbox
Solution: The FHIR resource is invalid. Check Aidbox logs for detailed validation errors.
Viewing Uploaded Resources
Access Aidbox UI:
- Navigate to Aidbox instance URL
- Go to REST Console or Database tab
- Query resources:
GET /StructureDefinition?url=http://mona.icu/StructureDefinition/SubEncounter
Resources and References
External Documentation
- FHIR Shorthand: https://build.fhir.org/ig/HL7/fhir-shorthand/
- SUSHI Documentation: https://fshschool.org/docs/sushi/
- Aidbox Documentation: https://docs.aidbox.app/
- FHIR R4 Specification: https://www.hl7.org/fhir/
Repository
- mona3-fhir-definitions: Repository Link (Internal GitLab)
Support
For questions about custom resources or the FSH workflow, contact the FHIR implementation team or open an issue in the repository.