Exit Full View

Generating HTML using Kotlin's DSL

I've used a few different approaches to generate HTML.

  • Java Server Pages
  • Templating Engine (I even wrote my own back in the day - Don't reinvent the wheel Nick!)
  • Kotlin's HTML DSL (The subject of this post)

If you haven't tried it, I strongly recommend Kotlin's HTML DSL (Domain Specific Language)

You can use it stand-alone, but I use it in conjunction with Ktor.

It is so much better than using a templating engine, and also much better than Java Server Pages.

We keep all the power of Kotlin and we don't have to learn a new language (we do need to learn a new API though, but IMHO, this is very easy).

Advantages

  • Our HTML is now guaranteed to be syntactically correct.
    • No mismatched open/close tags.
    • No missing quotes for attribute values.
    • No typos in tag names or attribute names
    • No unescaped special characters in attribute values or text.
  • No wasted white-space (you can turn the pretty printer on/off : either human readable or compact).
  • Streamed for minimum lag. The beginning of the html is sent to the client immediately, we render the html on the fly.

Down Sides

  • It is slightly more verbose than hand crafted HTML.
  • The DSL can be confusing to newcomers. The receiver changes often i.e. the meaning of "this" changes every time you enter a new html tag. This can get even more confusing when it is combined with other frameworks (such as Ktor) which also change the receiver. Coding standards should state that only one DSL within a function. For example, place your Ktor routing in a different function from the generation of the html.
  • Web designers may want to use "regular" html editors, to create page templates. Either they change their ways, or there is an additional step to convert the html template into the DSL syntax. Somebody has probably written code which does the conversion. Google is your friend.

Why Templating Engines are a PITA

Let's ignore the fact that we have to learn a whole new language, templating languages work at the wrong level of abstraction. They only know about text not tags. So they never help you get the syntax correct.

Are they Turin-complete? If we need to do some whacky manipulation of a piece of text can the templating engine handle it?

Consider an example. A web application which shows messages from a database, and the message can contain hashtags. Does the template know how to parse the hashtags and generate the appropriate links, or is that the job of the code feeding the template?

All the templating engines I've looked at, would be horrible to parse a block of text. So we have to spoon feed the template, splitting the message up into pieces of text and hashtags. Some other tasks may be handled by the template though, so now we have two very different places where processing is done.

By comparison, using a DSL, we would have something like :


    div {
        h3{ +message.title }
        p { parseTags( message.text ) }
    }

"parseTags" is a regular Kotlin function which looks for hash tags, and outputs plain text interspersed with <a> tags for each hashtag it finds. Note that it will be an extension function of one of the DSL's types (probably FlowContent). As a bonus, if the message is long, then we will start streaming it before the text is fully parsed. We will not incur extra latency. Our website will be more responsive.

Why JSP Is Rubbish

In the example above, we would create a custom JSP tag which parses the message and outputs the plain text interspersed with <a> tags. No additional latency either. So far so good.

However, creating a custom JSP tag is a royal PITA compared to writing a simple function.

Because JSP is an alien language, we cannot use our IDE's to quickly jump to the implementation in the same way we can with a regular Kotlin function (maybe IDEs have got better since I last used JSP).

The implementation of the custom tag is in Java (or Kotlin), not in JSP language, so we are changing language again. If the custom tag wants to use a feature that is also used within the JSP it cannot (it's a different language). Yes, we *could* have out custom tag use a snippet of JSP, but then we are really getting really convoluted, switching back and forth between languages.

Testing is much harder

Imagine we want a unit test which checks that the message "Hello #john" gets rendered to html correctly. We need to start up a JSP engine, and test using a http client of some kind.

If we used an HTML DSL, we could just render to a StringBuffer instead of the a webserver response, and do a simple string comparison. No web engine, no http client.

This is because JSP is so tightly intertwined with the http protocol, it cannot be separated. Why? Grr.

Even trivial reuse is painful with JSP

Part of this site has "edit" buttons to the right of the top-level headings. If I were using JSP, each one would be hand coded without reuse, because the effort of writing a custom jsp tag is too high for something so simple (and used infrequently).

Using kotlin's DSL, just create a function like so :

    fun FlowContent.edit(href: String, aTitle: String = "Edit") {
        div("floatRight") {
            a(href) {
                title = aTitle
                img("edit", "/resources/edit.png")
            }
        }
    }

All it does it create a <div> tag with the appropriate css class and uses a standard image as the <a> tag's content.

We then use it in our DSL like so :

   edit( "/editSomethingsURL" )
   h2{ + "Hello World" }

NOTE, you could do something similar using a template macro, but it wouldn't be as easy to use because it is an alien language which your IDE doesn't support as well as it does Kotlin.