1 of 22

Klite

github.com/codeborne/klite@antonkeks

Simple zero-deps non-blocking web apps in Kotlin

2 of 22

Tallinn, Estonia

3 of 22

About me - Anton Keks

24 years working in software

Co-founded Codeborne 12 years ago

Agile geek, software craftsman, conference speaker

Did custom projects for many diverse customers� fintech, energy, telecom, other cool stuff

Formerly in Java (even taught Java in TalTech)

Now a Kotlin fan (seen my Kotlin Puzzlers?)

Frontends in Svelte + TypeScript

4 of 22

Kotlin web frameworks

Ktor - too big, hard to unit-test routes

Http4k - no async/coroutine support

Jooby/Kooby - too javaesque, problems with coroutines

SparkJava - only routes, depends on Jetty, no async

Javalin - no coroutines, 7k loc vs 1k loc

Spring - bloated, annotation-driven development is not right� (debugging and testing nightmare)

Any other - big, hard to debug, blocking, no first-class Kotlin

5 of 22

Klite goals

Kotlin should enable a simple and thin framework

Productivity, no boilerplate

Memory usage & decent performance

Small runtime, few dependencies (no log4j2)

“Native” for Kotlin & coroutines

Running in a (Docker) container, 12-factor compatible

App code should be mostly framework-agnostic

Easy to write pure unit tests

6 of 22

JDK HttpServer

Official part of JDK since 1.6 (2006)

Since Java 9 - module jdk.httpserver

JavaHttpServerDemo.kt

Can serve 100 concurrent requests in ~1ms each

Your app spends much more time on DB or other I/O

7 of 22

Klite (Kotlin-lite)

Klite is a thin wrapper around jdk.httpserver

Runs http request handlers in coroutines

Started in Dec 2021 as a POC

Now powers 3 production projects

The main server module is ~800 loc

184kb jar, no other dependencies

8 of 22

Kotlin features used most

Expressive nullability (great for zero-code validation)

Constructors with default values

Extensibility with extension functions

Reified generics (with typeOf<>)

Type-safe reflection

Delegation, including lazy

Value classes (but still no good support in Jackson)

And single-expression functions :-)

9 of 22

Main parts

Config

Server

Context (Router) -> handlers

HttpExchange

request & response

10 of 22

Body & content-type handling

BodyParser

Looked up according to Content-Type request header

BodyRenderer

Looked up according to Accept request header

plain/text & x-www-form-urlencoded by default

Or use<JsonBody>()

UTF-8 by default

Return Unit for 204 No Content response�

11 of 22

Error handling

Exceptions are mapped by ErrorHandler to ErrorReponse �Also rendered by BodyRenderer

Some common Kotlin exceptions are mapped to nice responses,�e.g. NoSuchElementException to 404 NotFound

12 of 22

Annotated routes

Instead of

get {}

post {}

annotated<MyRoutes>()

@Path, @GET, @POST, etc

@PathParam, @QueryParam, @BodyParam, etc

Converter is used to convert strings to param types, e.g. UUID, LocalDate, etc

Allows most of the code to be framework-agnostic and easily testable

Annotations are for annotating, not changing of behaviour!

13 of 22

Registry

For internal and application components

Constructor-based dependency injection

Annotated routes get their parameters injected

Dependencies auto-created when first required

Default values used if no implementation registered

14 of 22

Decorators

They decorate route handlers, i.e. run around them

For logging, transaction handling, etc

Before & After also supported, both converted to decorators

Route handlers’ decorators are defined before them

15 of 22

Logging

Java System.Logger (since Java 9)

val logger = logger()

RequestIdGenerator - sets Thread name (instead of MDC)

RequestLogger

Can be redirected to slf4j

Implements simple logging to stdout as text or json

16 of 22

Session

Disabled by default

SessionStore

implementation can be provided to Server

CookieSessionStore

Encrypted cookies

No in-memory, as you want many nodes and restart them

17 of 22

Assets

AssetsHandler

Serves static files with caching headers

(can use pre-gzipped files)

SPA support: useIndexForUnknownPaths=true

18 of 22

Running behind a https proxy

As most applications do�

XRequestIdGenerator

To handle X-Request-Id

XForwardedHttpExchange

X-Forwarded-For, X-Forwarded-Host, X-Forwarded-Proto

19 of 22

Server-side HTML

Koltin Template strings (triple-quotes)

Use + for HTML escaping

”””Hello <b>${+world}</b>”””

Use IDEA’s @Language(“html”)

Or implement BodyRenderer using any template engine

20 of 22

Optional Modules…

jackson

vs kotlinx-serialization

jdbc

liquibase (app user)

jobs

i18n

slf4j

21 of 22

Best Practices

12-factor apps

Assets for SPA (e.g. using Svelte + Vite)

Routes, dependency injection

TestData

22 of 22

Conclusion

Started as a POC, is now quite enjoyable and productive

Hopefully inspires you to strive for simplicity

JVM + Kotlin = powerful mix

Steal ideas!

Fork it if you want! Send PRs

Or just use it :-)

github.com/codeborne/klite��jitpack.io/#codeborne/klite