I was watching Systems with JT the other day and he demoed a hobby operating system called skiftOS. During the demo he ran one of the built-in apps called “neko” which looks like a clone of an old Windows “pet” program I remember from my childhood, also called “neko” (or “neko32”). It’s a really simple program: when you start it up, a cute little kitten shows up on your screen and starts running around, trying to catch your mouse cursor.
Inspired by Brian Adkins’ RacketCon talk from yesterday, I decided to record a screencast on what it’s like to write a little web application using my not-quite-a-web-framework, koyo. You can watch it over on YouTube and you can find the resulting code on GitHub. It’s unscripted and I don’t go too deep on how everything works, but hopefully it’s easy enough to follow and I’ve left the various mistakes I’ve made in since it’s usually helpful to watch someone get out of a tricky situation so look forward to those if you watch it!
Someone recently asked about how to deploy Racket web apps on the Racket Slack. The most common answers were install Racket on the target machine, then ship your code there or use Docker (basically a “portable” variant of option 1). I wanted to take a few minutes today and write about my preferred way of deploying Racket apps: build an executable with the application code, libraries and assets embedded into it and ship that around.
Yesterday I released http-easy, a high-level HTTP client for Racket. I started working on it after getting annoyed at some of the code in my racket-sentry package. The same day I wrote that code, someone started a mailing list thread asking for a “practical” HTTP client so that served as additional motivation to spend some time on this problem. Here’s a basic example: 1 2 (require net/http-easy) (response-xexpr (get "https://example.com")) It might not seem like much, but even just that gets you automatic connection pooling.
In The Missing Guide to Racket’s Web Server, I said that dispatch/servlet is equivalent to: 1 2 3 (lambda (start) (lambda (conn req) (output-response conn (start req)))) That was an oversimplification. It does apply its start argument to incoming requests and it does take care of writing the responses to the appropriate connections, but it has another important job: to handle responses returned from continuations and to dispatch incoming requests to captured continuations.
A little over a year ago, I wrote about how you could use the GitHub’s new-at-the-time Actions feature to test Racket code. A lot has changed since then, including the release of a completely revamped version of GitHub Actions and so I thought it was time for an update. A Basic Package Let’s say you’re working on a Racket package for computing Fibonacci sequences. Your main.rkt module might look something like this:
Racket’s package manager doesn’t currently have the notion of locking package sets to specific versions1 per project so, as someone who operates a couple production Racket applications, I’ve been concerned about the possibility that new deployments could introduce bugs in production due to changing dependencies. To solve this problem, over the past weekend I’ve put together a service that creates daily snapshots of the official package catalog. You can find it at racksnaps.
For a project that I’m working on, I have a custom flake id spec that allows me to generate unique, sortable identifiers across computers without any sort of synchronization. The ids themselves can be encoded down to 16 bytes and I wanted to store them in Postgres. A good way to do that is to leverage Postgres’ UUID data type, which lets you efficiently store any 16 byte quantity in a way that can be indexed reasonably well.
Yesterday, I announced rackcheck, my new property-based testing library for Racket and I wanted to do a quick dive into one of the examples in the rackcheck repo where a simple web API is integration tested using PBT. You can find the full example here. The app being tested is a simple leaderboard HTTP API with 3 endpoints: GET /players: lists all the registered players in order from highest score to lowest.