An age of "ten" on a sign-up form
A college coding club puts a sign-up form online. Within a day the list has a person with no name, an email with no @ sign, and an age of "ten".
Nobody was being clever. People make typing mistakes, and nothing checked. Today you see where those checks go, and write one yourself.
By the end of this lesson
Note
I can check what a user types into a form.
Key words
| Word | What it means | Example |
|---|---|---|
| Form | the part of a page where you type answers and send them | |
| Field | one box on a form | |
| Validation | checking that what was typed follows the rules | |
| Client side | done in the user's browser | |
| Server side | done on the server, after the data arrives | |
| Constraint | a rule the database itself refuses to break | age between 16 and 18 |
The cells students fill in are left blank in this preview.
The browser can check a field
A web page builds a form out of fields. HTML can give each field a rule. required means it cannot be empty. type="email" wants an address with an @ sign. min and max set the smallest and biggest number.
These are client side checks: the browser does them before anything is sent.
Try the browser's own checks
<h1>Coding club sign-up</h1>
<form>
<p><label>Name <input name="name" required></label></p>
<p><label>Email <input name="email" type="email" required></label></p>
<p><label>Age <input name="age" type="number" min="16" max="18" required></label></p>
<p><button>Send</button></p>
</form>
<p id="result"></p>
The browser's checks can be skipped
The browser's checks only run on that page. Anybody can skip the page and send a request straight to the server, as curl does.
So the server has to check again: server side. In the lab the rules go into the database as constraints. The database refuses any row that breaks one, whoever sent it.
Before you start the Runs
Note
Press Start the lab and wait until it says it is running. Press the Runs in order. The first four make a signups table with three rules. The name and email cannot be empty. The email needs an @ sign, and the age is 16 to 18.
Give psql the password
export PGPASSWORD=shopShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Start with a clean table
psql -h db -U shop -c "drop table if exists signups"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Make a table with rules
psql -h db -U shop -c "create table signups (id serial primary key, name text not null, email text not null check (email like '%@%'), age int not null check (age between 16 and 18))"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Tell the API to look again
psql -h db -U shop -c "notify pgrst, 'reload schema'"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Send a sign-up that keeps every rule
curl -s -w "\n%{http_code}\n" -X POST -H "Content-Type: application/json" -d '{"name":"Maya","email":"[email protected]","age":17}' "http://api:3000/signups"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Reading a refusal
The last line of each Run is the status code. 201 means the row was stored.
A refusal is 400, which means the request was wrong. Above it the API sends JSON that says why. Look for "code" and "message": the message names the rule that was broken.
Send a sign-up with no name
curl -s -w "\n%{http_code}\n" -X POST -H "Content-Type: application/json" -d '{"email":"[email protected]","age":16}' "http://api:3000/signups"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Send an age of 25
curl -s -w "\n%{http_code}\n" -X POST -H "Content-Type: application/json" -d '{"name":"Ivy","email":"[email protected]","age":25}' "http://api:3000/signups"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
A common mistake
Warning
Many people think the browser's checks are enough. They only help honest users fix a typing mistake. Your Runs skipped the page completely. So every rule is checked again on the server, and the browser's checks are only a help.
A check written in Python
def check_age(text):
# A form always sends text, even for a number.
if not text.isdigit():
return "age must be a whole number"
age = int(text)
if age < 16 or age > 18:
return "age must be 16 to 18"
return "ok"
# Change "17" to "ten", then to "25", and press Run each time.
print(check_age("17"))
Going further: a weak email rule
Send leo.example.com as an email in the lab: copy the good Run, change the name and the email, and press Enter. The database refuses it.
Now think about @, a single @ sign on its own. Would the lab's rule accept it? What would a better rule check?