Thursday, June 29, 2017 [Tweets] [Favorites]

Type-Safe HTML in Swift

Brandon Williams:

An alternative approach to views is using “embedded domain specific languages” (EDSLs). In this approach we use an existing programming language (e.g. Swift), to build a system of types and functions that models the structure of the domain we are modeling (e.g. HTML).


We can use the type system to provide safety around how plain text is encoded for use with HTML. It allows us to prove that non-encoded strings never make it into our HTML.


Once you go down the road to thinking of views as functions (Data) -> [Node], you start to build up lots of lil helper views that can be reused in (hopefully) any which way. However, you soon find out that the data these subviews demand needs to be threaded all the way through the view hierarchy all the way back to the root view. This naturally leads one to something known as a Reader and solves this problem in a beautiful way.

Brandon Williams:

In our previous article we described how to build an EDSL to model HTML in Swift. Here we describe how to take our Node value type and render it to a string that can actually be served to the browser.

Brandon Williams:

Now we are going to tackle a problem that goes up one layer in the web-server request lifecycle: creating views. These are the things responsible for taking some data, say a list of articles, and creating the HTML to represent that data. It may sound easy, but there are a lot of difficult problems to solve with views. We want our views to be composable so that we can create small sub-views focused on rendering one piece of data and be able to reuse it. We also want our views to be flexible enough for future developments that are hard to see right now.


Comical code masturbation, replacing low-level HTML tags with low-level Swift code. Even a simple hand-coded HTML document easily runs to dozens of tags. Most of those elements are completely static, so assembling those with low-level code provides negative benefits (unnecessary runtime overhead, no HTML editing or preview tool suppport).

Useful high-level API abstractions would allow simple, foolproof construction of complex elements (lists, tables, forms, etc) in a fraction of the code. *That* would be a useful design language. Yet even obvious trivial cases such as unordered list (ul) elements don't make the obvious optimization of treating all items as list item (li) elements automatically; nope, the poor user has to declare all those li elements herself. Creating new document outlines (html, head, title, encoding, JS+CSS links, body elements) in a single call would be another obvious abstraction; still arguably a needless duplication of effort (compared to starting with a pre-written template), but at least that's approaching a *human design language*, as opposed to yet another useless vanity salve for impentrable nerd OCD.

The joke is, of course, that because such toy code has absolutely zero comprehension of how HTML works, it isn't "type-safe HTML" at all. You can put any HTML (or made-up) element inside any other HTML (or made-up) element to produce that is completely invalid as HTML. At least with handwritten HTML you can run the document through HTMLTidy to check it's well-formed as you type; or just use a GUI editor that knows how to construct HTML documents right.

Programmers have been inventing this "code-as-HTML" API over and over again for the last couple of decades, and there's a reason it's never caught on as a popular solution: because it's worse-than-useless make-work that increases, not decreases, the pain and cost of web page development.

(Which is not to say I like crap like Mustache either, being classic cases of Greenspun's Tenth Rule. But at least they treat the problem space like they understand it, respecting its complexity and not overstepping their own bounds, instead of twisting and hammering it to make it fit into their own level of stupid.)

@has I’ve been very happy with a similar Python library that does make sure that you can only use the proper attributes and nesting, and it’s easy to add the list-type conveniences that you speak of. So I think the general approach is sound. IMO, if you want to validate the HTML you should do that with the final page at the end, not try to validate an intermediate form. Except for very simple cases, I find the template approach to be the worst of both worlds. You lose the benefits of pure markup but only gain a weak set of programming tools.

Wow, way too harsh there, @has. I think the fact that this code ignores the HTML spec (what elements can live where, etc.) is a valid criticism.

I can't get down with the rest of your comment, though. “High-level” HTML frameworks have been done before and have their own set of problems.

This stuff strikes me as a great foundation with which to build such a framework, if one were so inclined — at least it's got the plumbing for true composability and is honest about the types.

Stay up-to-date by subscribing to the Comments RSS Feed for this post.

Leave a Comment