Use this file to discover all available pages before exploring further.
FHIRQueryValidator separates problems into two categories: errors that make a query invalid, and warnings that flag queries which are syntactically correct but may produce surprising results. Understanding this distinction—and writing code that responds appropriately to each—is the foundation of reliable FHIR integration. This guide covers every practical pattern for consuming ValidationResult objects, from simple if checks to aggregated batch reports.
Errors mean the query is structurally or semantically invalid. A FHIR server will reject it, or return undefined behavior. Always treat errors as blockers: do not send a query that has errors.
Warnings
Warnings mean the query is valid FHIR syntax but has a characteristic that may return unexpected results—such as a wildcard _include, a deprecated parameter, or an overly broad search. The query can be sent, but you should review the warning and decide whether to proceed.
from fhir_query_validator import FHIRQueryValidatorvalidator = FHIRQueryValidator()result = validator.validate_query("Observation?patient=Patient/123&_include=Observation:*")# result.is_valid is True even when warnings are presentprint(result.is_valid) # Trueprint(result.errors) # []print(result.warnings) # ["Wildcard _include may return a very large bundle"]
result.is_valid is True when there are no errors. Warnings do not affect is_valid. A result can have is_valid == True and a non-empty warnings list at the same time.
The simplest guard is an if result.is_valid check immediately after validation:
result = validator.validate_query("Patient?name=Smith")if result.is_valid: # Safe to use the query send_to_fhir_server(query)else: # Do not send; handle the failure handle_invalid_query(result)
Avoid inverting the check (if not result.is_valid: raise ...) without also handling the happy path—it’s easy to accidentally fall through to code that uses the query even when validation failed.
Both result.errors and result.warnings are plain Python lists of strings. Iterate over them directly:
result = validator.validate_query("Patient?birthdate=01/15/1990&unknown=foo")for error in result.errors: print(f"Validation error: {error}")for warning in result.warnings: print(f"Validation warning: {warning}")
When both lists are empty and result.is_valid is True, the query passed cleanly with no caveats.
For code paths where an invalid query is a programming error (rather than a user input error), raise an exception immediately:
def require_valid_query(validator, query: str) -> str: """Validate a query and raise ValueError if it has errors.""" result = validator.validate_query(query) if not result.is_valid: error_detail = "; ".join(result.errors) raise ValueError( f"Invalid FHIR query: {error_detail!r}\nQuery: {query!r}" ) return query
For user-facing code where the query comes from input, prefer returning the ValidationResult to the caller so they can display the errors themselves rather than catching an exception.
Use a custom exception type (e.g., FHIRQueryValidationError) instead of ValueError when you want callers to be able to distinguish FHIR validation failures from other value errors in the same call stack.
Structured logging makes it easy to trace validation outcomes in production systems:
import logginglogger = logging.getLogger(__name__)def validate_and_log(validator, query: str): result = validator.validate_query(query) if result.is_valid: if result.warnings: logger.warning( "FHIR query valid with warnings", extra={"query": query, "warnings": result.warnings}, ) else: logger.debug("FHIR query valid", extra={"query": query}) else: logger.error( "FHIR query invalid", extra={"query": query, "errors": result.errors}, ) return result
Log at debug for clean queries, warning when warnings are present, and error when the query is invalid. This keeps routine validations out of production log noise while surfacing problems clearly.
Collect and aggregate errors from validate_batch()
validate_batch() returns a list of ValidationResult objects in the same order as the input queries. To find all invalid queries in a batch, zip the inputs with the results:
queries = [ "Patient?name=Smith", "Observation?badparam=x", "Encounter?status=finished", "MedicationRequest?unknown=y&date=not-a-date",]results = validator.validate_batch(queries)invalid = [ (query, result) for query, result in zip(queries, results) if not result.is_valid]print(f"{len(invalid)} of {len(queries)} queries are invalid:")for query, result in invalid: print(f" {query}") for error in result.errors: print(f" ERROR: {error}")
To count unique error messages across a batch—useful for identifying recurring problems:
from collections import Counterall_errors = [ error for result in results for error in result.errors]for message, count in Counter(all_errors).most_common(): print(f" ({count}x) {message}")
Write assertions in tests using validation results
ValidationResult works naturally with assert statements and test framework assertions:
pytest
unittest
import pytestfrom fhir_query_validator import FHIRQueryValidatorvalidator = FHIRQueryValidator()def test_valid_patient_query(): result = validator.validate_query("Patient?name=Smith&birthdate=gt1980-01-01") assert result.is_valid, f"Expected valid query; errors: {result.errors}"def test_invalid_date_format_produces_error(): result = validator.validate_query("Patient?birthdate=01/15/1990") assert not result.is_valid assert any("date" in e.lower() for e in result.errors), ( f"Expected a date-related error; got: {result.errors}" )def test_wildcard_include_produces_warning(): result = validator.validate_query( "Observation?patient=Patient/1&_include=Observation:*" ) assert result.is_valid assert result.warnings, "Expected at least one warning for wildcard _include"
For audit logs, pre-flight checks, or developer tooling, build a structured report from a batch validation run:
from dataclasses import dataclass, fieldfrom fhir_query_validator import FHIRQueryValidator@dataclassclass QueryReport: query: str valid: bool errors: list[str] = field(default_factory=list) warnings: list[str] = field(default_factory=list)def build_validation_report(queries: list[str]) -> list[QueryReport]: validator = FHIRQueryValidator() results = validator.validate_batch(queries) return [ QueryReport( query=query, valid=result.is_valid, errors=list(result.errors), warnings=list(result.warnings), ) for query, result in zip(queries, results) ]def print_report(reports: list[QueryReport]) -> None: total = len(reports) valid_count = sum(1 for r in reports if r.valid) print(f"Validation report: {valid_count}/{total} queries valid\n") for report in reports: status = "PASS" if report.valid else "FAIL" print(f"[{status}] {report.query}") for error in report.errors: print(f" ERROR: {error}") for warning in report.warnings: print(f" WARNING: {warning}")# Example usagequeries = [ "Patient?name=Smith", "Observation?patient=Patient/123&status=final", "Encounter?badparam=x",]reports = build_validation_report(queries)print_report(reports)
1
Collect all queries
Gather every query string you want to validate into a single list—from configuration files, query builders, or user input.
2
Run validate_batch()
Pass the full list to validate_batch() to get results in one call.
3
Map results to report objects
Pair each query with its ValidationResult and convert to a plain data structure that’s easy to serialize or display.
4
Surface the report
Print, log, or serialize the report. Fail a CI check, send to a monitoring system, or display in a developer UI—the structure is the same regardless of output target.
The QueryReport dataclass in this example is a starting point. Add fields like timestamp, resource_type, or source as needed for your use case. The validator itself only provides is_valid, errors, and warnings—all other metadata comes from your application.