Full stack examples of how to use Hotwire JS in Kotlin services

Overview

hotwire-kt

A collection of Kotlin examples using the Hotwire JS framework to build interactive web apps with a Kotlin Armeria server backend.

Using Hotwire and kotlinx.html together has made building web apps fun again since I can build everything I want in sweet, sweet Kotlin.

Limitations

Notably, the lack of WebSocket support in Armeria limits it being a complete backend for Hotwire JS. For example, Turbo Streams which require WebSockets do not currently work. Turbo Links and Turbo Frames work well. WebSocket support is being tracked here and hopefully will be added soon.

Workflow

With the HTML to kotlinx.html IntelliJ Plugin, I could copy pasta any HTML UI code I found into a Kotlin file, and the corresponding kotlinx.html DSL would be generated and just work.

The one caveat is that for certain custom tags or attributes or somecases like ButtonType where kotlinx.html uses an enum you'll need to manually fix the DSL. Any required fixes were always straight forward in my testing.

The overall workflow of copying HTML from UI frameworks like Tailwind CSS, refactoring into Turbo Frame components, and adding props data classes for component inputs, proved to have the best of the React workflows I was used to without all the bad complex abstractions of React, Redux, Webpack, CSS-in-JS, and other novelties of the modern JS front end stack.

import xyz.adrw.hotwire.html.hotwire.turbo_frame
import xyz.adrw.hotwire.html.infra.template
import kotlinx.html.*

data class TableProps(
  val data: List<List<String>>,
  val limit: Int? = null,
  val query: String? = null,
)

val TableId = "table_frame"

val Table = template<TableProps> { props ->
  val header = props.data.first()
  val dataRows = props.query?.let { query ->
    props.data.drop(1).filter { row ->
      row.any { it.contains(query) }
    }
  } ?: props.data.drop(1)
  val truncated = dataRows.take(props.limit ?: 5)

  turbo_frame(TableId) {
    div("flex flex-col") {
      div("-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8") {
        div("py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8") {
          div("shadow overflow-hidden border-b border-gray-200 sm:rounded-lg") {
            table("min-w-full divide-y divide-gray-200") {
              thead("bg-gray-50") {
                tr {
                  header.map {
                    th(classes = "px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider") {
                      attributes["scope"] = "col"
                      +it
                    }
                  }
                    ...

The request lifecycle of encoding inputs within the request path and using a when statement to choose which component to return with new props was simple and straightforward, a joy to write and use.

/**
 * Endpoint that handles interactive UI from Hotwire Turbo Frame related clicks
 * Configuration of which UI to return and input data (ie. from forms) is provided by query parameters
 */
class TurboServiceHtml {
  private val logger = getLogger<TurboServiceHtml>()

  @Get
  @Produces("text/html")
  fun get(params: QueryParams): String {
    val screen = params[ScreenParam]
    val currentValue = params[BooleanParam].toBoolean()
    val searchQuery = params[SearchParam]
    val limit = params[LimitParam]?.toIntOrNull()

    return buildHtml {
      Wrapper("") {
        when (screen) {
          NavbarMobileMenuId -> NavbarMobileMenu(NavbarMobileMenuProps(visible = !currentValue))
          NavbarAvatarMenuId -> NavbarAvatarMenu(NavbarAvatarMenuProps(visible = !currentValue))
          TableId -> Table(TableProps(carsData, limit, searchQuery))
          TableWithQueryId -> TableWithQuery(TableWithQueryProps(carsData, limit, searchQuery))
          else -> logger.error("GET [screen=$screen] not found")
        }
      }
    }
  }
}

Resources

You might also like...
A repository full of Forge 1.8.9 Kotlin utilities

kotlin-forge-api kotlin-forge-api is a repository full of different APIs to be used by mods for Forge 1.8.9 to make modding easier! Warning! To use an

🧶 Full-fledged Kotlin client for MikaBot/cluster-operator as a separate package

🧶 Eri Full-fledged Kotlin client for MikaBot/cluster-operator as a separate package Usage Connecting to operator fun main(args: ArrayString) {

Lucilla - Fast, efficient, in-memory Full Text Search for Kotlin

Lucilla Lucilla is an in-memory Full Text Search library for Kotlin. It allows t

Simple application showing wallets fetched from fake services

LittleWallet Resume Simple application showing wallets fetched from fake services. User can filter wallets by currency types and click to enter a deta

Examples of Getting Started vídeos

Getting Started Kotlin Learn the basics of getting started with kotlin --- Repo: Kotlin Koans --- --- Repo: Problems Kotlin --- --- Rep

Sample Ktor app using a functional stack

samstack This is a template project you can clone and use as a basis for your own Kotlin based microservices. This application structure is my persona

Sample Ktor app using a functional stack

samstack This is a template project you can clone and use as a basis for your own Kotlin based microservices. This application structure is my persona

Starter project with PEKK stack.

Running the project To run the project, you need to run the server and the frontend. Running the server In the terminal, run ./gradlew narcore-server:

AndroidIDE - an IDE for Android to develop full featured Android apps on Android smartphones.
AndroidIDE - an IDE for Android to develop full featured Android apps on Android smartphones.

AndroidIDE - an IDE for Android to develop full featured Android apps on Android smartphones.

Comments
  • Add Misk Db Feature example of Misk-Web tab backed by Hotwire

    Add Misk Db Feature example of Misk-Web tab backed by Hotwire

    • [x] Merge existing kotlinxhtml and ui packages with new in /hotwire/*
    • [x] Update READMEs docs for new package locations and instructions
    • [x] Set service logs to INFO, not DEBUG
    • [x] Refactor handler / html to tighten up pattern
    • [x] Add support for all types with string input but backend validation and errors shown in UI
    • [x] Add deleted support or remove the UI
    • [x] Add breadcrumbs back to tab home on details and form pages

    Punted

    • Attempt to use FeatureMatcher instead of proto as core data structure. Serializing with Moshi seems like it would be challenging given use of Kotlin lambda and generics. Proto model probably is sufficient and can be replaced later if necessary.
    • Create bespoke /lib/_tab...tab_feature.js which adds necessary imports to <head/>k, check in to git, and delete all other JS (package.json, miskTab...). Manually writing JS is awful. Generated code is only 10kb so going to ignore this painful over-optimization for now.
    opened by adrw 0
Owner
Andrew (Paradi) Alexander
Software Engineer @cashapp. University of Waterloo CS '18.
Andrew (Paradi) Alexander
📒 NotyKT is a complete 💎Kotlin-stack (Backend + Android) 📱 application built to demonstrate the use of Modern development tools with best practices implementation🦸.

NotyKT ??️ NotyKT is the complete Kotlin-stack note taking ??️ application ?? built to demonstrate a use of Kotlin programming language in server-side

Shreyas Patil 1.4k Dec 26, 2022
Kotlin microservices with REST, and gRPC using BFF pattern. This repository contains backend services. Everything is dockerized and ready to "Go" actually "Kotlin" :-)

Microservices Kotlin gRPC Deployed in EC2, Check it out! This repo contains microservices written in Kotlin with BFF pattern for performing CRUD opera

Oguzhan 18 Apr 21, 2022
It is a project that contains lessons and examples about Kotlin programming language. 🇰

Kotlin Tutorials What is Kotlin? I added the platforms it supports and great resources. You can access the article from the link below: https://medium

Halil Özel 94 Dec 22, 2022
Kotlin Examples Problems

Kotlin Examples Problems --->>> Repo: Getting Started Kotlin <<<--- --->>> Repo Kotlin Koans <<<--- --->>> Repo: GameBoy Emulator Enviroment <<<--- --

Victor Bolinches 22 Oct 3, 2022
Kotlin Unit Testing Examples

Kotlin Unit Testing Examples Table of Contents Application Gradle, Kotlin & Groovy Junit4 Junit5 KotlinTest Spek Mockito Mockito-Kotlin Mockk Strikt T

Jarosław 110 Dec 11, 2022
kotlin koans examples

Kotlin Koans Build --->>> Repo: Getting Started Kotlin <<<--- --->>> Repo: Problems Kotlin <<<--- --->>> Repo: GameBoy Emulator Enviroment <<<--- --->

Victor Bolinches 121 Oct 3, 2022
101 examples for Kotlin Programming language.

This is a collection of runnable console applications that highlights the features of Kotlin programming language. The use of console application enab

Dody Gunawinata 192 Dec 1, 2022
Getting started Kotlin - Examples and explanations

Getting started Kotlin I'm learning Kotlin, so I have been updating it with examples and explanations about the language that I'm using at work. Proje

Jean Jacques Nascimento Barros 2 Apr 25, 2022
Examples for using Kotlin at a basic level for Android application development.

Kotlin Android Jetpack Basics Ejemplos para usar Kotlin a nivel básico para el desarrollo de aplicaciones Android. Kotlin Android Jetpack Basics Acerc

José Luis González Sánchez 2 Jun 28, 2022
A coding examples project about Kotlin Programming language. 🇰

Kotlin Tutorial ????‍?? What is Kotlin ❓ Kotlin is a new programming language, developed by JetBrains. Jetbrains is a popular software development com

Mustajab Ikram 4 Oct 11, 2022