@tmcw
Val Town API: Find a val by handle and name
This val fetches itself via the Val Town API! Weird, right?
TODO List
Every web project needs a todo list, right? This is val.town's first (maybe?) With a healthy dose of htmx and web fundamentals, we're packing the essentials of a TODO list with server persistence and animations into about 60 lines. The data is stored in the @tmcw.todos val, for now. Try it out.
Get a DuckDB database
This method sets up a duckdb-wasm database that you can then use to store and retrieve data.
Unfancy blocks
In the old days, there was a website called bl.ocks.org which re-hosted content on GitHub Gists and displayed visualizations made in those gists. It wasn't shiny but it was well-crafted and for the little community that used it, it was very nice.
This is a much worse, but very small, version of the same kind of program. This also shows you stuff from blocks. It displays readmes, with Titus's lovely micromark. It uses Ian's collected search index of bl.ocks.org to show you examples and thumbnails. It uses Alpine to pull together a little interface. And, of course, Val Town to make it all work.
The Big Story
This val, along with @tmcw.big_story, which requests from the New York Times API, and @tmcw.big_stories_ranks, which contains the data, generates a visualization of top stories on the NYTimes homepage.
This is here just to ask the question – what happens to cover stories over time? Do they slowly drop down the page, or just get replaced by a fully new lede? So far it doesn't have quite enough data to answer that question.
But also, it might be neat because it'll show which kinds of stories make the front page - is it climate, war, politics, or something else?
Quick poll
https://tmcw-poll.express.val.run
This val, along with a val called poll_results
and a val called poll_options
, lets you conduct a little poll using just Val Town! With the express API, this exposes a web interface in which people can click an option and vote. We make sure everyone only votes once by setting a cookie in their browser.
This uses htmx to make the voting experience slick, Tailwind to style the UI, and htm to generate HTML for the pages.
If you want to use this yourself, fork this val, the poll_results val, and the poll_options val, and customize the options list. You can delete the existing results as well to clear the data.
This tracks the data produced by my iPhone trade-in values val.
Track iPhone trade-in prices
iPhone trade in values - to trade phones back to Apple themselves - fluctuate over time, and eventually they no longer accept certain kinds of phones. You can still trade in an iPhone 7 - released in 2016, about 6 years ago as of this writing. But no longer does an iPhone 6 have value back to Apple.
This tracks those values - it runs every month and records prices to iphoneTradeInValues
, which I'll visualize once there's some data.
The story behind HTTP 200 "OK"
What's in an HTTP response? I've been writing software for the web since the early 2000s and have incrementally learned things about HTTP. There are status codes, like "200" and "404". There are headers, for Content-Type and headers to control cache settings. There are different versions of HTTP itself, like 1.1, 2, and 3. HTTP requests and responses can contain data, in the message body.
But there's one thing I didn't notice until yesterday. A quirk that was included in the HTTP 1.1 specification with an authors note that it's mostly there for historical reasons: the reason-phrase.
None of this information is useful. The reason-phrase is barely supported on the web and was always an oddity, but keep reading if you like oddities!
If you're used to JavaScript’s fetch()
method to make HTTP requests, you've seen the reason-phrase
under a different name: statusText
:
(await fetch('https://example.com/')).statusText
What is statusText
? I had assumed that it was something that JavaScript itself provides, by looking up the status code 200 and matching it with the text "OK". I was wrong!
When I look at a raw HTTP response, I see the first few lines are like this:
HTTP/1.1 200 OK
Date: Thu, 17 Aug 2023 15:16:42 GMT
Content-Type: text/plain;charset=UTF-8
The reason phrase
So what is that text? I dug around in the HTTP 1.0 specification and found the section Status Code and Reason Phrase.
The Status-Code element is a 3-digit integer result code of the attempt to understand and satisfy the request. The Reason-Phrase is intended to give a short textual description of the Status-Code. The Status-Code is intended for use by automata and the Reason-Phrase is intended for the human user. The client is not required to examine or display the Reason-Phrase.
That also lists recommended reason phrases, like OK for 200 and Not Found for 404. And notes that you can choose different phrases without affecting the protocol.
The HTTP 1.1 specification adds a little color about the reason-phrase:
So, with a HTTP server, you can customize your reason phrase! Here's an example with a val on Val Town:
let customReason = (req) =>
new Response("", {
statusText: 'Hello world!',
});
Unfortunately, this doesn't work! The response that Val Town produces is reorganized and optimized by Cloudflare, which upgrades requests and responses from HTTP 1.1 to HTTP 2. And sadly, HTTP 2 dropped support for the custom reason-phrase.
RIP the reason-phrase
. It was present even in a 1992 draft of the HTTP specification, and was a weird and under-appreciated way to pilfer extra information in a response. Now, thanks to HTTP/2 and the commonplace use of proxies and CDNs like Cloudflare, it's no longer usable. It was fun while it lasted.
WebFinger
This is a not-quite-complete ActivityPub implementation based on my blog post about building an AP implementation. It includes enough to look up bot@tmcw-activitypub.web.val.run
on Mastodon and get some basic information.