Skip to main content
Glama
validation.py8.79 kB
"""Validation functions for OpenFDA API responses.""" import logging from typing import Any from .exceptions import OpenFDAValidationError logger = logging.getLogger(__name__) def validate_fda_response( response: dict[str, Any], required_fields: list[str] | None = None, response_type: str = "generic", ) -> bool: """ Validate FDA API response structure. Args: response: The FDA API response dictionary required_fields: List of required top-level fields response_type: Type of response for specific validation Returns: True if valid Raises: OpenFDAValidationError: If validation fails """ if not isinstance(response, dict): raise OpenFDAValidationError( f"Expected dict response, got {type(response).__name__}" ) # Default required fields for most FDA responses if required_fields is None: required_fields = ["results"] if "results" in response else [] # Check required fields missing_fields = [ field for field in required_fields if field not in response ] if missing_fields: raise OpenFDAValidationError( f"Missing required fields in FDA response: {', '.join(missing_fields)}" ) # Type-specific validation if response_type == "search": validate_search_response(response) elif response_type == "detail": validate_detail_response(response) return True def validate_search_response(response: dict[str, Any]) -> bool: """ Validate FDA search response structure. Args: response: FDA search response Returns: True if valid Raises: OpenFDAValidationError: If validation fails """ # Search responses should have results array if "results" not in response: raise OpenFDAValidationError("Search response missing 'results' field") if not isinstance(response["results"], list): raise OpenFDAValidationError( f"Expected 'results' to be a list, got {type(response['results']).__name__}" ) # If meta is present, validate it if "meta" in response: validate_meta_field(response["meta"]) return True def validate_detail_response(response: dict[str, Any]) -> bool: """ Validate FDA detail response structure. Args: response: FDA detail response Returns: True if valid Raises: OpenFDAValidationError: If validation fails """ # Detail responses usually have a single result if "results" in response: if not isinstance(response["results"], list): raise OpenFDAValidationError( f"Expected 'results' to be a list, got {type(response['results']).__name__}" ) if len(response["results"]) == 0: # Empty results is valid (not found) return True if len(response["results"]) > 1: logger.warning( f"Detail response contains {len(response['results'])} results, expected 1" ) return True def validate_meta_field(meta: dict[str, Any]) -> bool: """ Validate FDA response meta field. Args: meta: Meta field from FDA response Returns: True if valid Raises: OpenFDAValidationError: If validation fails """ if not isinstance(meta, dict): raise OpenFDAValidationError( f"Expected 'meta' to be a dict, got {type(meta).__name__}" ) # Check for results metadata if "results" in meta: results_meta = meta["results"] if not isinstance(results_meta, dict): raise OpenFDAValidationError( f"Expected 'meta.results' to be a dict, got {type(results_meta).__name__}" ) # Validate pagination fields if present for field in ["skip", "limit", "total"]: if field in results_meta and not isinstance( results_meta[field], int | float ): raise OpenFDAValidationError( f"Expected 'meta.results.{field}' to be numeric, " f"got {type(results_meta[field]).__name__}" ) return True def validate_adverse_event(event: dict[str, Any]) -> bool: """ Validate an adverse event record. Args: event: Adverse event record Returns: True if valid Raises: OpenFDAValidationError: If validation fails """ if not isinstance(event, dict): raise OpenFDAValidationError( f"Expected adverse event to be a dict, got {type(event).__name__}" ) # Key fields that should be present (but may be null) important_fields = ["patient", "safetyreportid"] for field in important_fields: if field not in event: logger.warning(f"Adverse event missing expected field: {field}") return True def validate_drug_label(label: dict[str, Any]) -> bool: """ Validate a drug label record. Args: label: Drug label record Returns: True if valid Raises: OpenFDAValidationError: If validation fails """ if not isinstance(label, dict): raise OpenFDAValidationError( f"Expected drug label to be a dict, got {type(label).__name__}" ) # Labels should have OpenFDA section if "openfda" not in label: logger.warning("Drug label missing 'openfda' section") # Should have at least one section label_sections = [ "indications_and_usage", "contraindications", "warnings_and_precautions", "adverse_reactions", "dosage_and_administration", ] has_section = any(section in label for section in label_sections) if not has_section: logger.warning("Drug label has no standard sections") return True def validate_device_event(event: dict[str, Any]) -> bool: """ Validate a device event record. Args: event: Device event record Returns: True if valid Raises: OpenFDAValidationError: If validation fails """ if not isinstance(event, dict): raise OpenFDAValidationError( f"Expected device event to be a dict, got {type(event).__name__}" ) # Device events should have MDR report key if "mdr_report_key" not in event: logger.warning("Device event missing 'mdr_report_key'") # Should have device information if "device" not in event and "devices" not in event: logger.warning("Device event missing device information") return True def validate_recall(recall: dict[str, Any]) -> bool: """ Validate a recall record. Args: recall: Recall record Returns: True if valid Raises: OpenFDAValidationError: If validation fails """ if not isinstance(recall, dict): raise OpenFDAValidationError( f"Expected recall to be a dict, got {type(recall).__name__}" ) # Required fields for recalls required = ["recall_number", "classification", "product_description"] for field in required: if field not in recall: logger.warning(f"Recall missing required field: {field}") # Validate classification if present if "classification" in recall: valid_classes = ["Class I", "Class II", "Class III", "1", "2", "3"] if recall["classification"] not in valid_classes: logger.warning( f"Invalid recall classification: {recall['classification']}" ) return True def sanitize_response(response: dict[str, Any]) -> dict[str, Any]: """ Sanitize FDA response to handle common issues. Args: response: Raw FDA response Returns: Sanitized response """ if not response: return {} # Handle fields that can be string or list if "results" in response and isinstance(response["results"], list): for result in response["results"]: if isinstance(result, dict): # Fields that can be string or list polymorphic_fields = [ "source_type", "remedial_action", "medical_specialty_description", "manufacturer_name", "brand_name", "generic_name", ] for field in polymorphic_fields: if field in result: value = result[field] # Ensure consistent list format if not isinstance(value, list): result[field] = [value] if value else [] return response

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/genomoncology/biomcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server