use std::fmt; use serde_json::{Value, json}; use fhir::FhirResource; #[derive(Debug, Clone)] pub struct ValidationError { pub message: String, pub pointer: String, } impl fmt::Display for ValidationError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "[{}] {}", self.pointer, self.message) } } pub fn validate_fhir_payload(data: &str) -> Result, Vec> { let parsed: Value = serde_json::from_str(data) .map_err(|e| vec![ValidationError { message: format!("Invalid JSON: {}", e), pointer: "#".to_string(), }])?; let mut errors: Vec = Vec::new(); if parsed.get("resourceType").is_none() { errors.push(ValidationError { message: "Missing top-level 'resourceType' field".to_string(), pointer: "#".to_string(), }); return Err(errors); } let resource_type = parsed["resourceType"].as_str().unwrap_or(""); if resource_type == "Bundle" { validate_bundle(&parsed, &mut errors); } else { validate_single_resource(&parsed, &mut errors); } if !errors.is_empty() { return Err(errors); } Ok(vec![parsed]) } fn validate_bundle(bundle: &Value, errors: &mut Vec) { if bundle.get("type").is_none() { errors.push(ValidationError { message: "Bundle must have a 'type' field (e.g., 'collection', 'transaction')".to_string(), pointer: "#/type".to_string(), }); } let entries = match bundle.get("entry") { Some(entries) => entries, None => { errors.push(ValidationError { message: "Bundle must have an 'entry' array".to_string(), pointer: "#/entry".to_string(), }); return; } }; let entries = match entries.as_array() { Some(arr