Development
Full Stack Web Development
A front end, a small API, and the path that connects them.
Full Stack Web Development shows both sides of a small product: pages people use, and a server that stores and returns data. You will see how a request travels, how a response is shaped, and how the interface uses it. Earlier HTML, CSS, and JavaScript will help.
Course syllabus
01. The shape
- Front end, API, and data
What each layer is responsible for.
- A request and a response
The browser asks, and the server answers with a status, headers, and a body.
- JSON for the body
A small object with named fields, which the page can read without scraping a paragraph.
- The database holds the record
The page shows a copy that can be stale or edited, and the stored row is the record.
- Learn it on one machine
The page and the API run locally before you involve a host.
- A folder for each side
You can point at the file that runs in the browser and the file that runs on the server.
- A tutorial is not a finished product
A missing check is a hole, not a style you leave in because the demo is small.
- The one record you will store
One kind of thing, with a few fields, so the path stays visible.
02. The screen
- A screen that asks for data
A page that can show loading, a result, and an error.
- Fields that match the record
Each input has a label, and the labels are the fields you decided to store.
- The form hint is not the rule
The browser can nudge, and the server still has to refuse a bad body.
- A list under the form
The records you have loaded, empty until the first successful read.
- Open one record from the list
A click shows that record's fields, so reading is part of the screen.
- One submit at a time
Disable the button while a request is in flight so you do not create three copies.
- Words for success and failure
A message in text, not only a colour.
- Make it work before you style it
Labels and behaviour first, and appearance after the data moves.
03. Routes
- Routes and responses
A request, a status, and a JSON body.
- GET does not write
A read should leave the stored data as it was.
- POST creates
A body with the new record, and a response that says whether it was stored.
- Status codes you will return
200, 201, 400, and 404, each for a reason you can say out loud.
- An error body without a stack trace
A short message the page can show, and no internal detail in the response.
- Say that the body is JSON
A content-type header so the client knows how to read the body.
- Allow only your page's origin
The front end you are building, not a wildcard you copied and forgot.
- Call the route without the page
A request from the terminal, so you know the API works on its own.
04. The server
- A process on a port
A start command, a port, and a log line when the server is listening.
- A handler per path
Each route in its own function, rather than one block that does everything.
- Parse JSON or reject it
Read the body as JSON, and return a 400 when it is not.
- An id in the path
The URL names one record, and the handler uses that id to look it up.
- Unknown id is a 404
Tell the client the record is not there, rather than returning an empty success.
- A list in a stable order
The records you are willing to show, sorted the same way each time.
- Secrets stay on the server
A database password never appears in the front-end code.
- The same routes after a restart
Stop the process, start it, and the paths are still there.
05. The record
- A table with an id
Columns for the fields, and an id the database assigns.
- The page never opens the database
Only the server holds the connection.
- Saving and reading a record
Create something, then fetch it back.
- The insert returns the new id
The response includes the id the database just created.
- One row or none
A lookup by id returns the record, or it returns nothing.
- The columns the screen needs
Select what the page will show, not every internal column.
- Blank is not the same as missing
Decide what you store for an empty field, and what you refuse to store.
- Confirm the row with a query
Look at the table, not only at the API response.
06. Wiring
- Wiring the page to the API
The full round trip on one feature.
- The API address in one place
Host and port live in one value, not copied into every call.
- POST the form with fetch
Send JSON, and check the status before you treat the save as done.
- Load the list when the page opens
A GET on load, then render the rows you got back.
- Show the record you just saved
Use the response or reload the list so the screen matches the table.
- Show the server's error
Put the 400 message where the person can read it.
- When the request never returns
Say that the network failed, and leave the form filled in.
- The detail comes from a GET
Opening a row fetches that record, rather than trusting a copy on the page.
07. Checks on the server
- What not to trust from the browser
Checks that belong on the server.
- A missing field is a 400
A body without a required name does not become a row.
- Type and length
Reject a value of the wrong type, and reject a body past the size you set.
- Trim, then decide
Spaces around a value are not a name.
- The client does not set the id
Ignore an id or a role the browser sends, and set those on the server.
- One function for the rules
Create uses it, and a later update would use the same function.
- A bad body from the terminal
Send an invalid payload and expect a 400.
- A valid body and the row it creates
The smallest acceptable body, and the row that appears after it.
08. When it fails
- Logs and responses are different
You may log a detail on the server, and the response stays short.
- A duplicate you chose to reject
The same email twice gets a clear error, if you decided that value must be unique.
- A failed write is not a success
If the database did not store the row, do not tell the client it worked.
- Do not hang the page
A slow database gets a timeout the page can show.
- A guessable id is not a password
If people can try ids, do not treat the URL as a secret.
- Do not fake a login
This app has no accounts, and a hidden field is not one.
- The server decides what is allowed
When you add users later, the server still checks permission on every request.
- What this app does not protect
No passwords, no payments, and no private data you are not ready to store.
09. The page people use
- A label focuses its field
The label is tied to the input, so a click on the words focuses the box.
- The list is a real list
Use a list or a table, not a pile of divs with no role.
- A button that submits
The control is a button, and Enter in the form still submits.
- Words when the list is empty
A sentence that says there are no records yet.
- Words while the list is loading
The list shows that the read is still in flight.
- Keep the form when the save fails
The person can fix a field and try again.
- Clear the form only after a save
Reset the fields when the server confirms the write, not when it returns an error.
- The page still makes sense unstyled
With the stylesheet off, the labels and the messages still explain the screen.
10. Running it
- Start the API and the page
Two processes, and the order you start them.
- Port and database URL outside the code
Read them from the environment, not from a value pasted in the source.
- Commands a classmate can follow
How to install, how to start, and which URL to open.
- One known row to start from
A seed record so the list is not empty the first time.
- A missing setting stops the process
If the database URL is absent, exit with a message rather than a blank failure.
- The page calls the port you started
The client address matches the server you just launched.
- The row survives a restart
If you claimed the database stores it, stop the server and see the row again.
- Method, path, and body on one page
A short list of the routes, so you can test them later without rereading the code.
11. What this is not
- What you can point at
A page, a few routes, and one table.
- A second kind of record
Another table and another set of routes, using the same pattern.
- Update and delete use the same checks
A change or a removal would run the same server-side rules as create.
- A library does not replace the check
A helper can organise the rules, and the rules still run on the server.
- Values go in as parameters
Pass input as a parameter so it is not concatenated into the query text.
- A name is text, not HTML
Render a stored name as text so it cannot run as a script.
- Leave secrets out of the log
Do not print passwords, tokens, or full connection strings.
- The next gap you will close on purpose
Accounts, deployment, or tests, and a sentence about what this app still lacks.
Lecture videos stay with the course. Playback for enrolled students will open once payments are available. Video links are not published on this page.
