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<String>,
},
}
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