FHIR Builder
fyron.fhir.builder creates FHIR JSON resources and bundles from explicit Python inputs. It is for clinical data science workflows where extracted observations, conditions, imaging measurements, generated summaries, model endpoints, and provenance need to become inspectable FHIR JSON.
Fyron uses plain dictionaries instead of generated model classes. That keeps resources easy to print, diff, validate, write to disk, and post through FHIRRestClient.
If your extracted findings already live in a reviewed CSV or DataFrame, use FHIR Mapping on top of these builders.
Choose Your Builder Path
Single Resource
Build one `Observation`, `Condition`, `DocumentReference`, or `DiagnosticReport` for a small write-back task.
LLM Evidence
Package extracted facts with the source report, model endpoint, generated summary, and `Provenance`.
Imaging Measurements
Write BOA, radiomics, or model-derived measurements linked to a study and series UID.
Server Upload
Use `transaction` bundles when submitting to a FHIR server; use `collection` bundles for local review.
Version Policy
FHIR R4 is the default and stable target:
version = "R4"FHIR R6 can be selected with version="R6", but Fyron marks the output as experimental. Use R6 only for prototypes or when your implementation guide explicitly expects it.
Fyron validates structure, required fields for the resources it builds, transaction metadata, and local references. It does not replace your server validator, the official HL7 validator, or implementation-guide profile validation.
Imports
from fyron.fhir.builder import (
build_bundle,
build_condition,
build_document_reference,
build_imaging_measurement_bundle,
build_llm_extraction_bundle,
build_observation,
build_observation_component,
codeable_concept,
loinc,
icd10,
summarize_fhir_bundle,
validate_fhir_bundle,
validate_fhir_references,
write_fhir_json,
)Resource Anatomy
| FHIR part | Why it matters in Fyron workflows |
|---|---|
subject | Usually the patient reference, for example Patient/123. |
code | The clinical meaning of the resource. Prefer LOINC, SNOMED CT, ICD-10, DICOM, or a local code system. |
value[x] | Observation value, such as valueQuantity, valueString, valueBoolean, or valueCodeableConcept. |
component | Multi-part observations, for example systolic and diastolic blood pressure. |
derivedFrom | Evidence link from an extracted observation to a source document or imaging study. |
evidence.detail | Evidence link from a condition to a source report. |
result | DiagnosticReport references to grouped observations. |
Provenance.target | Resources generated by a model, extractor, or analysis workflow. |
Minimal Observation
from fyron.fhir.builder import build_bundle, build_observation, loinc, summarize_fhir_bundle, write_fhir_json
observation = build_observation(
subject="Patient/123",
code=loinc("33747-0", "Status"),
value="no evidence of progression",
value_type="string",
observation_id="obs-status-001",
)
bundle = build_bundle([observation], bundle_type="collection")
summary = summarize_fhir_bundle(bundle)
write_fhir_json(bundle, "outputs/fhir/evidence_bundle.json")Generated shape:
{
"resourceType": "Observation",
"id": "obs-status-001",
"status": "final",
"subject": {"reference": "Patient/123"},
"code": {"coding": [{"code": "33747-0", "system": "http://loinc.org", "display": "Status"}]},
"valueString": "no evidence of progression"
}Multi-Component Observation
Use components for values that belong together clinically.
from fyron.fhir.builder import build_observation, build_observation_component, loinc
blood_pressure = build_observation(
subject="Patient/123",
code=loinc("85354-9", "Blood pressure panel"),
components=[
build_observation_component(code=loinc("8480-6", "Systolic blood pressure"), value=124, unit="mm[Hg]"),
build_observation_component(code=loinc("8462-4", "Diastolic blood pressure"), value=77, unit="mm[Hg]"),
],
)If a value was expected but unavailable, use data_absent_reason instead of inventing a placeholder.
missing_marker = build_observation(
subject="Patient/123",
code="PD-L1 tumor proportion score",
data_absent_reason="not measured",
)LLM Extracted Evidence
This pattern keeps a model-extracted result auditable: the source report is a DocumentReference, extracted observations use derivedFrom, extracted conditions use evidence.detail, the generated summary is a DiagnosticReport, and Provenance links everything to the model.
from fyron.fhir.builder import build_condition, build_llm_extraction_bundle, build_observation, icd10, loinc
hemoglobin = build_observation(
subject="Patient/123",
code=loinc("718-7", "Hemoglobin"),
value=13.4,
unit="g/dL",
observation_id="hgb-001",
)
condition = build_condition(
subject="Patient/123",
code={"coding": [icd10("C34", "Malignant neoplasm of bronchus and lung")]},
condition_id="condition-lung-cancer",
)
bundle = build_llm_extraction_bundle(
subject="Patient/123",
source_report_url="https://reports.example.org/report-001.pdf",
observations=[hemoglobin],
conditions=[condition],
summary_text="LLM-generated summary for clinical review.",
model_name="Fyron LLM extractor",
model_endpoint_url="https://models.example.org/fyron/extract",
model_version="2026.06",
prompt_version="report-extraction-v1",
id_prefix="report-001",
bundle_type="collection",
)Imaging Measurements
Use this pattern for quantitative values derived from an imaging study and a specific series.
from fyron.fhir.builder import build_imaging_measurement_bundle, codeable_concept
bundle = build_imaging_measurement_bundle(
subject="Patient/123",
study_instance_uid="1.2.840.113619.2.55.3.604688654.123",
series_instance_uid="1.2.840.113619.2.55.3.604688654.123.4",
series_description="CT abdomen portal venous",
measurements=[
{
"id": "l3-sma",
"code": codeable_concept(text="L3 skeletal muscle area"),
"value": 123.4,
"unit": "cm2",
"body_site": codeable_concept(text="L3"),
"method": codeable_concept(text="BOA/Fyron segmentation workflow"),
},
{
"id": "vat-volume",
"code": codeable_concept(text="Visceral adipose tissue volume"),
"value": 820.5,
"unit": "ml",
"body_site": codeable_concept(text="Abdomen"),
},
{
"id": "vat-sat-ratio",
"code": codeable_concept(text="VAT/SAT ratio"),
"value": 0.74,
"unit": "ratio",
},
],
model_name="Fyron imaging measurement model",
model_endpoint_url="https://models.example.org/fyron/imaging",
id_prefix="study-001",
bundle_type="collection",
)The resulting observations point back to the ImagingStudy, include a series UID extension, and are grouped by a DiagnosticReport.
Bundle Anatomy
| Bundle type | Use | Entry request |
|---|---|---|
collection | Local evidence package, review artifact, JSON export. | No entry.request. |
transaction | Server write-back through the FHIR base URL. | Adds entry.request.method and entry.request.url. |
transaction = build_bundle(
[entry["resource"] for entry in bundle["entry"]],
bundle_type="transaction",
transaction_method="PUT",
)Use transaction_method="POST" for server-assigned IDs. Use transaction_method="PUT" when resources already have stable IDs. Conditional create is available for POST:
transaction = build_bundle(
[observation],
bundle_type="transaction",
if_none_exist={"Observation": "identifier=obs-status-001"},
)Inspect Before Writing
from fyron.fhir.builder import summarize_fhir_bundle, validate_fhir_bundle, validate_fhir_references
reference_report = validate_fhir_references(bundle)
summary = summarize_fhir_bundle(bundle)
validate_fhir_bundle(bundle)
print(reference_report["valid"])
print(summary["resource_types"])summarize_fhir_bundle() returns entry counts, resource-type counts, transaction methods, version tags, and local-reference status.
Posting To A FHIR Server
FHIRRestClient can post individual resources or transaction bundles using the same authenticated session as REST extraction.
from fyron import FHIRRestClient
from fyron.fhir.builder import build_bundle
client = FHIRRestClient("https://fhir.example.org/fhir")
transaction = build_bundle(
[entry["resource"] for entry in bundle["entry"]],
bundle_type="transaction",
)
result = client.submit_bundle(transaction)
print(result.status_code, result.location)create_resource, update_resource, and submit_bundle return FHIRWriteResult objects with status code, location, resource type, resource id, and response JSON when available.
Validation Levels
| Level | Tool | What it checks |
|---|---|---|
| Fyron structural validation | validate_fhir_resource, validate_fhir_bundle | Required fields for Fyron-supported resources, bundle type, transaction request metadata, local references. |
| Server validation | Target FHIR server | Capability statement, resource acceptance, server-side profiles, authorization. |
| Profile validation | HL7 validator or implementation guide tooling | Full conformance to R4/R6 profiles, terminology bindings, slicing, extensions. |
Function Parameters
Resource Builders
| Function | Required inputs | Optional inputs | Returns |
|---|---|---|---|
build_observation(...) | subject, code | value, value_type, unit, components, data_absent_reason, derived_from, performer, encounter, method, body_site, interpretation, note, version | Observation dict |
build_observation_component(...) | code | value, unit, value_type, data_absent_reason, interpretation | Observation component dict |
build_condition(...) | subject, code | clinical/verification status, onset, recorded date, evidence, version | Condition dict |
build_document_reference(...) | subject plus attachment values | title, content type, date, description, type, version | DocumentReference dict |
build_diagnostic_report(...) | subject, code | results, imaging study refs, conclusion, presented form, version | DiagnosticReport dict |
build_imaging_study_reference(...) | subject, study_instance_uid | series UID/description, modality, started, version | ImagingStudy dict |
build_model_device(...) / build_endpoint(...) | model or endpoint identity | version, endpoint link, manufacturer | Device/Endpoint dict |
build_provenance(...) | targets | agent, entity, recorded, activity, prompt version | Provenance dict |
Workflow Builders And Helpers
| Function | Required inputs | Optional inputs | Returns |
|---|---|---|---|
build_llm_extraction_bundle(...) | subject, source report URL, model name, bundle type | observations, conditions, summary, endpoint, model/prompt version, id_prefix, FHIR version | Bundle dict |
build_imaging_measurement_bundle(...) | subject, study UID, measurements, bundle type | series UID, model info, id_prefix, version | Bundle dict |
build_bundle(...) | resources, bundle type | bundle id, transaction method, conditional create, version | Bundle dict |
write_fhir_json(...) / read_fhir_json(...) | payload/path | none | path or payload dict |
summarize_fhir_resource(...) / summarize_fhir_bundle(...) | resource/bundle | none | summary dict |
validate_fhir_resource(...) / validate_fhir_bundle(...) | resource/bundle | version | validated dict or raises |
validate_fhir_references(...) | bundle | none | reference report dict |
Common Pitfalls
- Do not post
collectionbundles to a FHIR server as transactions. - Use
id_prefixwhen packaging multiple reports or imaging studies in one workflow. - Do not encode missing values as fake measurements; use
data_absent_reason. - Local references such as
Observation/obs-1must resolve inside the bundle if they point to generated resources. - R6 output is explicitly experimental.
- Fyron validation is a safety check, not regulatory-grade FHIR conformance.
Related Modules
- FHIR for REST queries and extraction.
- LLM for model-assisted extraction.
- Imaging and BOA for imaging-derived measurements.
- Audit & Provenance for analysis manifests outside FHIR.