Validating Input

Making sure bad data does not reach the database

Concepts

Why validation matters

Litestar's built-in validation

Custom validation

Returning validation errors to the user

Check for Understanding

What kinds of invalid input can Litestar's type-based validation catch automatically, and what kinds does it miss?

Type-based validation catches inputs that cannot be converted to the declared type (e.g., a string where a float is expected) and missing required fields. It cannot catch inputs that are the right type but the wrong value: a negative diameter is still a float, a future date is still a valid date, and a nonexistent site name is still a str. Custom validators are needed for those.

What is referential integrity, and why does a type annotation alone not enforce it?

Referential integrity means that a value in one table must correspond to an existing row in another table (e.g., the site name in a measurement must appear in the sites table). A type annotation can only say "this field is a string"; it has no way to check whether that string matches any row in the database. Enforcing referential integrity requires either a SQL foreign key constraint or a custom validator that queries the database.

Why is client-side (browser) validation not enough, even if it catches most mistakes?

A user can disable JavaScript, use browser developer tools to remove HTML5 attributes, or send an HTTP request directly with curl or a script, bypassing the browser entirely. Client-side validation is a convenience for honest users; server-side validation is the security boundary. Both are needed, but server-side validation must never be skipped.

If the server returns a validation error, how do you display the error message next to the right form field without losing the user's other inputs?

The server returns an HTML fragment (via HTMX) that contains the form with its fields pre-filled from the submitted values, plus error messages inserted next to the invalid fields. The HTMX response replaces the form element in the page, so the user sees their input intact and the error highlighted in context. A full-page redirect would lose all the filled-in values.

Exercises

Add range validation

Add validation that shell diameter must be between 0.1 mm and 50 mm. Before writing code, decide where this check belongs: HTML5 min/max attributes, a Litestar type annotation, a custom validator, a database constraint, or some combination. Write a one-paragraph justification, implement the chosen approach, and test it with values at the boundary (0.1, 50) and outside (0, 50.1).

Validate the site name

Add a custom validator that checks whether the submitted site name exists in the sites table. Write the validator function before asking the LLM. Compare your implementation to what the LLM produces. Note whether the LLM handles the case where the database connection is not available.

Test invalid inputs

Write three pytest tests that send invalid data to the add-record route: one with a missing required field, one with a diameter outside the valid range, and one with a site name that does not exist in the database. Assert that each test returns a 400 status code with a response body that mentions the specific field that failed.

Improve error messages

The default Litestar validation error messages are written for developers, not researchers. Find a way to replace or supplement them with plain-language messages suitable for a non-programmer. Ask the LLM for options, implement one approach, and verify the messages are clear to someone who has not read any of this tutorial.