# Form Processing: HTML Markup to HTTP Request — narration script
Runtime 10:55. Timecodes are when each chapter starts; the film's animation is keyed to these cue times, so a recorded voice-over should keep each line near its timecode.
## 0:00 · A form is a letter writer
- `0:01` Every HTTP message has three parts: a first line, a block of headers, and a body. Call it the Law of Three.
- `0:11` Links and images ask for things, with an empty body. A form is the one thing in plain HTML that writes a whole request, body and all, with no JavaScript at all.
- `0:26` Look at the form element, and you can predict the request it will write. The method attribute and the action fill the first line. The action's host and the encoding type become headers. And the fields, walked and encoded, become the body.
- `0:45` Three attributes and some named fields. Let's watch the browser fill in each part.
## 0:52 · The first line
- `0:52` The method attribute says what kind of request this is. Leave it off, and you get GET, the default.
- `1:00` The action says where it goes. Its path lands in the first line, and its host becomes the Host header. Write a relative action, and the page's own host fills in. Leave the action off entirely, and the form submits to the very page it's on. To say so explicitly, we often write #. Fun fact: a form that posts to its own page is an old web coding pattern called a postback.
- `1:32` So method="post" and action="https://cse134.site/api/echo" give us POST /api/echo HTTP/1.1, and Host: cse134.site.
- `1:50` HTML forms know only two HTTP methods, GET and POST. Other HTTP methods like PUT, PATCH and DELETE aren't supported.
- `2:03` Write method="put" anyway, and the browser doesn't complain. It quietly sends a GET.
- `2:11` There is one more value, dialog. It sends no request at all; it closes the dialog box the form sits in. That's a story for another tutorial.
- `2:25` The choice also decides where the data goes. With GET, the fields ride in the query string, on the first line, in the address bar, in history and in server logs. With POST, they travel in the body. GET asks a question. POST makes a change.
## 2:45 · The button has a say
- `2:45` Which button you press matters too.
- `2:49` If the button has a name, its name and value join the data, so the server can tell Save from Delete. Only the button you pressed is sent.
- `3:00` A button can also overrule the form. formaction, formmethod, formenctype and formtarget replace the form's own attributes, for that button only.
- `3:15` Our Preview button says formmethod="get". Press it, and the same fields go out as a GET, in the query string, to the same address. One form, two different requests.
- `3:31` That formtarget points at the last part of the trip: where the answer goes. The form's target attribute picks the window. The default, _self, replaces the page you're on. _blank opens a new tab. Or name an iframe, and the answer lands inside it.
- `3:53` Fun fact: before Ajax, a form aimed at a hidden iframe was how pages sent data without going anywhere.
## 4:03 · The walk
- `4:03` Now the body. When you press Send, the browser walks the form from top to bottom, in source order, collecting name and value pairs. This is called form serialization.
- `4:18` The name comes from the field's name attribute. The value is whatever the field holds right now. A field with an id but no name isn't sent at all. Not empty. Absent. Name and id serve different purposes: the name is for the server, and the id is for labels, styles and scripts.
- `4:41` Disabled fields are skipped too, and so are checkboxes nobody checked.
- `4:47` But read-only fields are sent. So are hidden ones. The user can't change them, but they're still part of the form.
- `4:56` That gives the server fullname, school, and source. The coupon was disabled, and the email field had no name, so the server never hears of either.
- `5:09` Fun fact: hidden fields were one of the web's first ways to remember things from page to page, and they still carry the little facts a server needs back, like which item you're buying.
## 5:22 · Preparing the payload
- `5:23` The pairs can't go out as they are. A space or an ampersand inside a value would break the format. So the browser encodes them, by the rules the encoding type attribute names. Enc type, for short.
- `5:39` The default is application/x-www-form-urlencoded. Pairs are joined with ampersands, spaces become plus signs, and anything risky becomes a percent sign and two hex digits. Joe O'Reilly becomes Joe+O%27Reilly.
- `5:59` The browser adds a Content-Type header naming the encoding, so the server knows how to unpack the body. That header is the label from Three Things, now on a request.
- `6:12` Now add a file input, and upload the cat photo. Forget to change the encoding, and the server receives the word cat.webp. Just the file's name. Not one byte of the cat.
- `6:28` Files need enctype="multipart/form-data". The body becomes a stack of parts, one per field, divided by a boundary string the browser invents. Each part gets its own small headers, and the file's part carries the actual bytes.
- `6:47` A third value, text/plain, exists too. It's not reliable to parse, so leave it alone. And notice what's missing: there is no JSON. An HTML form can't send it.
## 7:04 · Doing it yourself with JavaScript
- `7:05` Everything so far happens automatically, with no script. JavaScript can step in instead. Our code listens for the submit event, cancels it, and takes over the process.
- `7:18` Now our script owns the request. It can still borrow the browser's walk: new FormData(form) collects exactly the same pairs, skipping and including the same fields. Or we can collect them ourselves, by hand.
- `7:35` Careful, though. Hand that FormData to fetch, and it goes out as multipart, not as the form's default encoding. If your server expects the default, wrap it in URLSearchParams.
- `7:51` We have full control of the process, so our script can build the body itself: JSON, with an application/json label, and any method it likes, PUT, PATCH or DELETE. The three parts are the same. The script just writes them instead of the browser.
- `8:12` Fun fact: the form's limits became the web's security rule. A form could always post to any site, so a script may do the same, unasked, only if a form could have sent the request. Send JSON, or PUT, to another site, and the browser first asks that site for permission.
## 8:35 · Progressively enhanced forms
- `8:35` Be careful: scripts can fail. They're blocked, slow to load, or broken by an error on the page. Then the browser's own form is all your user has.
- `8:48` If the server endpoint only understands JSON, a form without JavaScript to enhance it is straight broken. Progressive enhancement means the HTML path works first, and the script makes it better.
- `9:04` So design for both. Give the form a real action and a real method, and keep its fields named. Need a method HTML doesn't have? Many servers read a hidden field, often called \_method, and treat the POST as a PUT or a DELETE.
- `9:22` Make sure your endpoint reads the Content-Type header and accepts both: form encoding when the HTML submits, JSON when the script does. That's a few lines on the server, and it keeps the form working for everyone.
- `9:40` And the validation the form does, like required fields and patterns, is for the user's convenience, not your security. Anyone can skip the form and send the server any packet they like, so do security checks on the server and keep HTML and JavaScript validation for UX improvements.
## 10:03 · Read what you sent
- `10:03` Try it. Point a form at https://cse134.site/api/echo and submit it. The answer should be your own request: the method, every header, and the raw body, exactly as the browser wrote it.
- `10:23` Then switch the method to GET, add a disabled field, press a button with a formmethod, or upload a file without changing the encoding, and watch the request change.
- `10:35` Method and action fill the first line. The host and the encoding type fill the headers. The form process fills the message body. A form, in effect, writes the HTTP packet for you.