Uploads FHIR configuration resources from a local directory to a FHIR server via the FHIR Gateway with Keycloak authentication.
This uploader works with OpenSRP 2 configs and content, including FHIR resources and app configuration files that should be uploaded as Binary resources.
The uploader is maintained in its own repository. When executing it, you can place
the script and config inside or outside the resources folder. The simplest setup is
to run it alongside the resources so resource_dir: "." works without extra path
management:
your-fhir-resources/
├── fhir_upload.py
├── upload-config.example.yaml
├── upload-config.yaml ← you create this (gitignored)
├── questionnaires/
├── structure_map/
├── plan_definitions/
├── app/ ← non-FHIR files (uploaded as Binary)
└── ...
Install uv (manages Python and dependencies automatically):
curl -LsSf https://astral.sh/uv/install.sh | sh # macOS / Linux / WSL
# powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" # WindowsThen:
cp upload-config.example.yaml upload-config.yaml
# Edit upload-config.yaml with your server URLs and resource_dir
export FHIR_UPLOAD_USERNAME=admin
export FHIR_UPLOAD_PASSWORD=secret
uv run fhir_upload.pyuv run fhir_upload.py [OPTIONS]
Options:
--config PATH Path to config YAML file [default: upload-config.yaml]
--dry-run Validate and show what would be uploaded, without uploading
--no-pull Skip git pull before uploading
--folder FOLDER[/PATH] Upload only this folder or subpath
--verbose Show full response bodies on failure
--help Show this message and exit
uv run fhir_upload.py # upload everything
uv run fhir_upload.py --dry-run # preview without uploading
uv run fhir_upload.py --folder questionnaires # single folder
uv run fhir_upload.py --folder app/profiles # subfolder
uv run fhir_upload.py --folder app/sync_config.json # single file
uv run fhir_upload.py --config staging-config.yaml # different config
uv run fhir_upload.py --no-pull # skip git pull
uv run fhir_upload.py --verbose # full response bodies on failureUse --folder FOLDER[/PATH] when you need to upload a single folder, subfolder, or file from an entry listed in processing_order. Copy upload-config.single.example.yaml to upload-config.single.yaml, then pass the target path with --folder.
In --folder structure_map/path/to/file.json, structure_map must be listed in processing_order; path/to/file.json is relative to the structure_map folder. Credentials should come from environment variables instead of the config file.
cp upload-config.single.example.yaml upload-config.single.yaml
# Edit upload-config.single.yaml with your server URLs and resource_dir
export FHIR_UPLOAD_USERNAME=admin
export FHIR_UPLOAD_PASSWORD=secret
uv run fhir_upload.py \
--config upload-config.single.yaml \
--folder structure_map/path/to/file.jsonCopy upload-config.example.yaml to upload-config.yaml and fill in your server URLs and resource paths. The config file is gitignored.
Each processing_order entry is either:
- A folder name, for normal FHIR JSON resources.
- A folder mapping with
resource_type, for non-FHIR files that should be uploaded as a specific FHIR resource type.
Folders containing plain files (JSON configs, HTML pages, etc.) can be uploaded as Binary resources by annotating the entry in processing_order:
processing_order:
- "questionnaires"
- name: "app"
resource_type: "Binary"Binary folders scan all file types (not just .json), derive the resource ID from the filename (e.g. sync_config.json → Binary/sync-config), and set Content-Type based on the file extension.
These override YAML values (use $env:VAR = "val" on Windows PowerShell):
export FHIR_UPLOAD_USERNAME=admin
export FHIR_UPLOAD_PASSWORD=secret
export FHIR_UPLOAD_CLIENT_SECRET=client-secret # for client_credentials grant| Grant type | When to use | Required fields |
|---|---|---|
password |
User account (default) | username, password |
client_credentials |
Service account / CI | client_secret |
The uploading user needs PUT_{RESOURCE_TYPE} roles for every resource type being uploaded. For a typical configuration upload:
PUT_QUESTIONNAIRE
PUT_STRUCTUREMAP
PUT_PLANDEFINITION
PUT_LIST
PUT_BINARY
PUT_COMPOSITION
The SUPERVISOR and WEB_ADMIN groups already include these roles.
| Dependency | Notes |
|---|---|
| Python 3.10+ | Handled automatically by uv |
| git | Required if resource_dir is a Git repo; install via your OS package manager |
| uv or pip | See Quick Start above |
| Code | Meaning |
|---|---|
0 |
All uploads succeeded |
1 |
One or more uploads failed, or one or more files were invalid |