Adding Records

Giving users a form to submit new snail measurements

Concepts

A POST route in Litestar

A data-entry form

Inserting the new record

Partial page updates with HTMX

What the LLM missed

Check for Understanding

What is the Post/Redirect/Get pattern and why does it prevent duplicate submissions on refresh?

After a successful POST, the server sends a redirect response (303 or 302) pointing to a GET URL (typically the updated table page). The browser follows the redirect and makes a GET request. If the user presses Refresh, the browser re-issues the GET, not the original POST. Without the redirect, refreshing would re-send the form data and insert a duplicate record.

If a form has method="post" and action="/add", what does the browser send to the server when the user clicks Submit?

An HTTP POST request to /add with a Content-Type: application/x-www-form-urlencoded header. The request body contains the form fields as URL-encoded key-value pairs (e.g., site=north-beach&diameter=14.2&mutated=true). The server must decode these values from the request body rather than from the URL.

What is a CSRF attack, and why does it only affect state-modifying requests?

A CSRF attack tricks the user's browser into sending a request to your server using the user's active session cookie. An attacker embeds a hidden form on their site that auto-submits to your /add route; the browser sends the request with the victim's cookies attached. It only affects POST/PUT/DELETE because GET requests should not modify state; CSRF tokens work by including a secret in the form that the attacker cannot know.

How does Litestar map HTML form fields to Python function parameters?

Litestar reads the Content-Type header to determine the encoding (form data vs. JSON), then parses the body and maps field names to the corresponding function parameters declared with Body(media_type=RequestEncodingType.URL_ENCODED) or a similar annotation. Field names in the HTML form must match the parameter names (or the fields in the annotated dataclass) exactly.

Exercises

Add client-side validation

Add HTML5 attributes to the form inputs to prevent obviously wrong values before submission: required on all fields, min="0.1" and max="50" on the diameter field, and type="date" on the date field. Test what happens when you submit the form with an empty required field or a diameter of -1. Note what the browser does versus what the server would have done.

Duplicate detection

Modify the server to check whether a measurement from the same site on the same date already exists before inserting. Decide whether to reject the duplicate with a 409 status, silently ignore it, or update the existing record. Implement your chosen behavior and add a brief comment explaining the rationale.

Multi-record upload

Add a route and form that accepts a CSV file upload and inserts all valid records from it. Ask the LLM for the HTML <input type="file"> markup and the Litestar handler code. Test with a file that contains a mix of valid and invalid rows and decide what to do with each.

Audit the LLM's output

Ask the LLM to add CSRF protection to the data-entry form. Read the code it produces carefully: does it actually prevent the attack described in this lesson? What would a test that verifies CSRF protection look like? Note any gaps between what the LLM claimed and what the code actually does.