# Error Handling and Resilience

## Overview

This codebase handles error conditions primarily through validation-driven recovery rather than exception-heavy control flow. In the pet management flow, invalid input is detected early, attached to Spring MVC `Errors`, and routed back to the same form so the user can correct the problem without losing context. The tests around `PetController` and `PetValidator` show the main resilience pattern: fail fast on bad data, preserve the model, and keep the request cycle predictable.

This approach matters because it keeps form processing safe and user-friendly. Instead of allowing malformed dates, missing required fields, or duplicate names to propagate deeper into the system, the application validates input before persistence and returns the form view with precise field-level feedback.

## Implementation Patterns

### Validation before persistence

The `PetValidator` is the main guardrail for pet form submissions. The validator is exercised directly in [`PetValidatorTests`](../src/test/java/org/springframework/samples/petclinic/owner/PetValidatorTests.java), where invalid names, missing types, and missing birth dates are each expected to produce field errors.

This gives the application a consistent pattern for handling user mistakes:

- validate the domain object
- attach field errors to the `Errors` object
- prevent the operation from continuing
- let the controller re-render the form

### Controller-level recovery

[`PetControllerTests`](../src/test/java/org/springframework/samples/petclinic/owner/PetControllerTests.java) shows how the web layer responds when validation fails. The controller keeps the user on `pets/createOrUpdatePetForm` and exposes the `pet` model attribute with errors rather than redirecting.

Common recovery behaviors covered by the tests include:

- blank pet name → `required` error code
- duplicate pet name → `duplicate` error code
- missing pet type → `required` error code
- invalid birth date format → `typeMismatch` or `typeMismatch.birthDate`

This means the controller does not try to "repair" invalid input silently. It surfaces the problem and returns the same form state to the caller.

### Binding and type conversion errors

Some failures happen before validation logic even runs. For example, malformed dates are reported as binding errors when Spring cannot convert the submitted value into a `LocalDate`. The controller tests assert these errors explicitly, which shows that the codebase treats binding failures as first-class validation outcomes.

### Nested error scenarios

The test classes use nested groups named [`ProcessCreationFormHasErrors`](../src/test/java/org/springframework/samples/petclinic/owner/PetControllerTests.java) and [`ProcessUpdateFormHasErrors`](../src/test/java/org/springframework/samples/petclinic/owner/PetControllerTests.java), plus [`ValidateHasErrors`](../src/test/java/org/springframework/samples/petclinic/owner/PetValidatorTests.java). That structure is a useful signal: resilience is not a special case here, but a standard part of the happy-path flow.

## Key Classes

### [`ProcessCreationFormHasErrors`](../src/test/java/org/springframework/samples/petclinic/owner/PetControllerTests.java)

A nested test group that documents creation-time recovery behavior. It verifies that invalid form submissions keep the user on the pet form and surface field-specific errors instead of completing the operation.

### [`ProcessUpdateFormHasErrors`](../src/test/java/org/springframework/samples/petclinic/owner/PetControllerTests.java)

A nested test group that documents the same recovery model for updates. This is important because edit flows often need the same safeguards as create flows, but with existing entity state already loaded.

### [`ValidateHasErrors`](../src/test/java/org/springframework/samples/petclinic/owner/PetValidatorTests.java)

A nested test group that documents the validator contract directly. It confirms that the validator is responsible for rejecting missing or malformed pet data at the domain boundary.

### [`PetValidator`](../src/test/java/org/springframework/samples/petclinic/owner/PetValidatorTests.java)

The central validation component for pet form data. It is the main example of defensive input handling in this area of the application.

### [`PetController`](../src/test/java/org/springframework/samples/petclinic/owner/PetControllerTests.java)

The web entry point that turns validation results into user-visible behavior. Its tests show the controller returning the same view for invalid submissions and redirecting only after successful processing.

## How It Fits Together

```mermaid
flowchart TD
A["User submits pet form"] --> B["PetController"]
B --> C["Spring binding"]
C --> D["PetValidator"]
C --> E["Binding errors"]
D --> F["Errors object"]
E --> F
F --> G["pets/createOrUpdatePetForm"]
F --> H["redirect:/owners/{ownerId}"]
G --> I["User fixes input"]
H --> J["Successful save and navigation"]
```

The flow is simple:

1. The controller receives form input.
2. Spring binds request values to the pet model.
3. Validation and type conversion produce errors when needed.
4. Errors are attached to the model and the form is re-rendered.
5. Only clean input progresses to redirect-after-success behavior.

## Notes for Developers

- Treat validation as the first line of defense. The tests show that invalid input should be caught before any successful transition occurs.
- Preserve the form view on failure. Returning `pets/createOrUpdatePetForm` keeps user context and makes correction easy.
- Distinguish binding failures from business-rule failures. A malformed date and a duplicate name are different kinds of problems, and the test suite expects different error codes for them.
- Keep controller recovery logic and validator rules aligned. If validation rules change, update both the validator tests and the controller tests so error handling remains consistent.
- Use nested test classes to document failure modes. The current structure makes resilience scenarios easy to scan and maintain.
- Prefer explicit field errors over generic failures. Field-level feedback is more actionable for users and easier to verify in tests.
