use serde_json::{Value, json}; use std::collections::HashSet; /// The set of top-level FHIR R4 resource types we accept. const KNOWN_RESOURCE_TYPES: [&str; 12] = [ "Patient", "Observation", "Condition", "Encounter", "Procedure", "MedicationRequest", "MedicationStatement", "MedicationDispense", "AllergyIntolerance", "DiagnosticReport", "Immunization", "CarePlan", ]; /// Outcome of validating a single inbound FHIR payload. #[derive(Debug, Clone)] pub enum ValidationResult { Valid, Invalid { message: String, /// JSON pointer to the offending field, e.g. "/resourceType". pointer: Option, }, } impl ValidationResult { pub fn is_valid(&self) -> bool { matches!(self, ValidationResult::Valid) } } /// Validate a raw FHIR R4 payload. /// /// Returns `ValidationResult::Valid` if the payload is a well-formed /// FHIR resource with a known resourceType, or `Invalid` with a /// human-readable message and a JSON pointer to the problem. pub fn validate_fhir_payload(raw: &str) -> ValidationResult { // Step 1: must be valid JSON. let value: Value = match serde_json::from_str(raw) { Ok(v) => v, Err(e) => { return ValidationResult::Invalid { message: format!( "Payload is not valid JSON: {}. FHIR R4 resources must be JSON objects.", e ), pointer: None, }; } }; // Step 2: must be a JSON object. let obj = match value.as_object() { Some(o) => o, None => { return ValidationResult::Invalid { message: "Payload must be a JSON object (FHIR resource).".to_string(), pointer: None, }; } }; // Step 3: required field "resourceType" must be present and a string. let resource_type = match obj.get("resourceType") { Some(Value::String(s)) => s.as_str(), Some(_) => { return ValidationResult::Invalid { message: "\"resourceType\" must