Skip to content

ADR-057: CR data must be validated with Pydantic models

Category: development Provenance: human

Decision

All Custom Resource data must be loaded into Pydantic models before use. Direct dictionary access to CR spec fields is prohibited. Type-safe Pydantic models enforce validation and provide IDE support.

Rationale

Pydantic validation catches configuration errors at reconciliation start, not during Keycloak API calls. Type annotations enable IDE autocomplete and static analysis. Prevents typos in field names - spec["reamName"] fails silently, realm_spec.realm_name catches typos. Enforces field constraints (required fields, value ranges, enum values). camelCase/snake_case conversion automatic via Pydantic aliases. Future schema changes handled in one place (models) instead of scattered dict access. Matches decision 013 (Pydantic for Keycloak API) - consistency throughout operator. Testing easier with typed models than dicts.

Agent Instructions

Always use KeycloakRealmSpec.model_validate(spec), KeycloakClientSpec.model_validate(spec), or KeycloakSpec.model_validate(spec) to load CR data. Never access spec fields directly as dict (spec["field"]). Models in src/keycloak_operator/models/ provide type safety, validation, and camelCase/snake_case conversion. Example: realm_spec = KeycloakRealmSpec.model_validate(spec). Access fields via attributes: realm_spec.realm_name not spec["realmName"]. Pydantic validates required fields, types, and constraints. Invalid specs raise ValidationError early. All handlers use this pattern - see src/keycloak_operator/handlers/realm.py line 346 and client.py line 350.

Rejected Alternatives

Direct dictionary access to CR spec

No validation until Keycloak API rejects it. Typos undetected. No IDE support. Type errors caught at runtime not development time.

Optional validation (validate if convenient)

Inconsistent. Some handlers validate, others don't. Leads to runtime errors in some paths.

JSON Schema validation only

CRD OpenAPI validation is first line of defense, but Pydantic provides Python-native types and IDE integration.