A Web App in OCaml with Dream and TyXML

background and motivation

I've made some progress with OCaml since I wrote my first steps with ocaml post. After that post, I started a project to load CSVs into a database so it'd be easier for me to query the data. This was initially a command-line tool but has since grown to include a REST API. Overall, that project has been really helpful for learning more about building an actual application with OCaml, a step up from solving the coding challenges on the OCaml website.

I now want to explore that data visually, and to do so I'd like to build a frontend component. However, before doing that, I'd like to kind of start over with a project that has a smaller scope. The goal for this smaller project is to explore the options for building frontend applications with OCaml. I've heard of a few things over the years - js_of_ocaml, ReScript, ReasonML - but I don't know how they work.

For this application, I wanted to work on an idea I'd been kicking around for a while: tracking pomodoros. I've used the pomodoro technique for years and have found it to be a very useful way of structuring parts of my day. However, for almost all of the time I've used this technique, I've done relatively little tracking of that work; I'd just set a timer and try to stay focused on one task for 25 minutes. Maybe I'd take a 5- or 10-minute break, sometimes I'd just keep going. I really only used the technique as a way of getting started and staying focused, not for reflection.

I kept going like that until about a year ago, when my wife mentioned she'd been writing down what she did during each pom (our shorthand for the standard 25-minute window). Even then, it wasn't until I started contracting (and needed to actually account for my hours) that I started doing the same. Since then, it's become a core part of my work routine.

implementation

This is, more or less, the smallest thing I could think of while still using the tools I'm interested in learning. The "architecture" is a backend web server with two endpoints and a sqlite database serving templated HTML. There's a form with fields for a title and a description, and then a list of my completed poms underneath that. Eventually I'll want to add things like start/stop fields to the form, and more interesting ways of displaying completed poms, but for now I just want an example of an end-to-end OCaml web app.

server

I'm using Dream for the server. I've seen some other Recursers build projects with it and the combination of their blog posts and Dream's extensive collection of examples made it very easy to get set up. It reminds me of HTTP servers I've used before, like Express and Flask, in that the core model seems to be a list of endpoint/function pairs. I'm sure that's skipping over a lot of details, but that mental model didn't really seem to get in my way at this point.

client

As the name of this post implies, I settled on using TyXML for frontend things rather than Dream's "Embedded ML" templating language. The reason for this is that, uh, TyXML worked with my emacs configuration right away, and EML didn't. I realize that's not exactly picking a technology on its merits, but I'm chalking this one up to "beginner's impatience", with the hope of potentially giving EML a more fair assessment in the future.

I'm using TyXML's Html package (instead of either the Reason/JSX syntax or the preprocessing syntax), mostly because I'm new enough to still be kind of weirded out by ppx stuff. Also, I've done a few Elm tutorials and this approach reminded me of Elm's HTML syntax, so there's probably also a bit of recognition there that drew me to this method. The TyXML basic_website example and Dream's TyXML example were super helpful to get started. I struggled a bit with translating HTML into TyXML's syntax, but I eventually got there.

One component I haven't bothered with yet is client-side scripting, which is kind of funny to me since that's the only part of OCaml's web ecosystem I was aware of before I got started. I think the reason I've stayed away (aside from the fact that client-side code is probably unnecessary for this project) is that I couldn't quickly tell which system would feel right to me. I was able to pretty quickly fall into a productive pattern with TyXML. I'm not sure I'm able to do that with any of the common client-side tools. I'm hesitant to try ReScript and ReasonML because I'd prefer to stick to OCaml (although who's to say where OCaml ends and the other begins?) but the js_of_ocaml code I've seen doesn't really look like it would bring the same joy that I've felt with OCaml so far. I also don't really know what the developer experience or ~~ ergonomics ~~ of each feels like, so I suspect that'll make for a decent follow-up post.

reflection

The more I work with OCaml, the more I enjoy it. My work from the past few years has been mostly Python, JavaScript/TypeScript, and SQL, and I've been kind of shocked at the salience of the relief I feel by relying on a strong type system. My head feels less cluttered. I get a more satisfying click in my head when my code runs. Sure, yes, TypeScript does have a really impressive type system, but it's also super easy to just kind of, like, opt out of it, undercutting the comfort gained from the type system's safety net.

I'm looking forward to writing more OCaml code, even if it's just on the side. Maybe it's just that I know the early versions were written in OCaml, but it does remind me a lot of Rust. I've enjoyed learning and writing Rust too, but I like OCaml's closer ties to CS theory and I haven't had to think about borrowing or lifetimes.

If you're interested in seeing a true novice at work, feel free to peruse the repo (I'll try to open up the CSV project at some point, too): https://gitlab.com/soryrawyer/pomocaml