The forty-third lesson of the Go course. The reader closed the tab, and the handler learns of it by itself: measured here, it drops the work after two hundred milliseconds. A deadline for a query, a key of your own type instead of a string, and the promised move of the signed-in person into the request's context.
The forty-second lesson of the Go course. Your server has been concurrent since the HTTP lesson and you did not choose it: every request is a goroutine of its own. Measured here: a counter without a lock first loses one reading out of five hundred, then brings the whole server down, and go test -race finds it beforehand.
The forty-first lesson of the Go course. The table promised back in lesson 10: the cases go into a list, t.Run gives each of them a name, and a failure says which case broke. Plus checking a handler without starting a server, and an honest word about what -cover really shows.
The fortieth lesson of the Go course. A form with a file in it, and four things checked before that file reaches the disk: its size, its type by content, a name of our own instead of the one sent, and where to put it. And /static gets a shape at last: brand, css, images, js, uploads.
The thirty-ninth lesson of the Go course. A stranger's script on your page, and another site submitting a form in your reader's name. Measured here: how html/template escapes by context — in text, in a link and inside a script — and how a token tells your form from somebody else's.
The thirty-eighth lesson of the Go course. Hiding a button is not a guard: it is measured here how a stranger edits your article with a direct request while never seeing the button. The check lives in the handler and in one place, and the refusals differ: a guest is sent to sign in, a stranger gets 403, and what does not exist gets 404.
The thirty-seventh lesson of the Go course. HTTP remembers nothing: every request arrives from a stranger. A cookie holding a user number is forged in a second. So the browser carries a random token, the database keeps its hash, and three words close the rest: HttpOnly, Secure, SameSite.
The thirty-sixth lesson of the Go course. A password is not kept in the database; a bcrypt hash is, with the salt inside it and the cost outside. Measured: sha256 does nine million hashes a second, bcrypt does ten. Plus the 72-byte limit a Kazakh password runs into at its thirty-seventh letter.
The thirty-fifth lesson of the Go course. Seven templates in the blog hold seven copies of the same start of a page. Today one frame is left: base with blocks, the folders pages and partials, semantic markup — and the measured trap that makes every page in somebody's blog suddenly show the same one.
The thirty-fourth lesson of the Go course. A search that works: an FTS5 virtual table, three triggers, ranking and highlighting. Plus a measured surprise: a parameter protects you from injection, but not from a person typing the word OR into the search box.
The thirty-third lesson of the Go course. An article has many tags and a tag has many articles — and that is kept in a table of its own rather than a list in a column. A composite key, on conflict for the sake of an id, a cascade on delete. And the promised way to ask an error for its code instead of reading its text.
The thirty-second lesson of the Go course. Two rules that keep a database whole. Data is never glued into the text of a query: a tampered address returns three rows instead of one, and through a parameter it returns none. And what has to happen together is wrapped in a transaction: without one, a counter went up for a move that never took place.
The thirty-first lesson of the Go course. The program stops creating the schema at start-up: numbered migration files appear, a journal of what has been applied, and the rule that each one runs exactly once. Plus a measured trap: a not null column with no default is accepted by an empty database and refused by a working one.
The thirtieth lesson of the Go course. Articles move out of a slice and into a database, and survive a restart. A Store type that hides the database from the rest of the code, four actions on an article, and one non-obvious thing worth a section of its own: updating what is not there is not an error, and RowsAffected is the only way to find out.
The twenty-eighth lesson of the Go course. An article acquires comments, and they do not fit inside it. A second table and the key between them, join against left join, cascading deletes, and the SQLite trap that leaves foreign keys silent and rows orphaned.
The twenty-seventh lesson of the Go course. Articles finally survive a restart. Why the course uses SQLite rather than Postgres, how to create a table and put a row into it: insert with returning, select with where and order by, an update whose where was forgotten, and the difference between = null and is null.
The twenty-ninth lesson of the Go course. The blog finally reads its articles out of a database file. The package and the driver, why sql.Open opens nothing, what a connection pool is, and why the foreign-keys pragma belongs in the connection string rather than in a query of its own. Plus ErrNoRows and checking for an error after the loop.
The twenty-sixth lesson of the Go course. The address, the database file and the signing key move out of the code. The flag package and what -h gives you, why an environment variable makes a convenient default for a flag, how an empty variable differs from an unset one, and why a missing required setting should stop the program at start-up.