Introducing OkSSE — Kotlin Multiplatform SSE library
At Clue, we always want to keep finding new solutions as challenges arise. Recently, we needed to build a dynamic UI driven via backend which motivated the entire team 💪🏻 and eventually led to the development of OkSSE library.
And today, I’m super excited 🎉 to share OkSSE — an open source Server sent events client library made with Kotlin multiplatform and Coroutine for the tech community to use and build their amazing use-cases.
OkSSE is a client for Server Sent events protocol written in Kotlin Multiplatform. The implementation is written according to W3C Recommendation 03 February 2015 specification 📝
OkSSE is an SSE client that’s modern, efficient and provides an easy-to-use API.
The aim of this article is to:
- walk you through our journey 🛣 ️of why we set out to use SSE protocol,
- explain why we decided to build our own library,
- and share how you can use the library for your use-cases
Backstory
We started with an idea 💡to have a backend driven UI and build an infrastructure for it. That’s where we decided to use SSE [Server Sent Events] protocol to talk with the mobile clients [Android & iOS] in order to continuously stream 🌊 the data from the backend to render the UI on clients.
Check out the talk below if you are interested in learning more about how we used SSE for Backend Driven UI:
What’s SSE?
Server-sent events (SSE) is a server push technology enabling a browser to receive automatic updates from a server via HTTP connection — Wikipedia
In a nutshell 🥜, SSE is built on top of well known HTTP and establishes a unidirectional connection from server → client. The server continuously pushes data downstream ⬇️, which clients can stream until the app or tab [for web] is closed.
Reinvent the wheel 🎡
With backend driven UI in mind, both of our client teams (i.e Android and iOS) started searching for the best way to implement SSE on their corresponding platforms. Naturally, we found plenty of other SSE implementations for mobile clients…
…But most of them needed to be modified to accommodate our needs, were not maintained, or did not fully meet the specifications.
Possible options
- Take existing libraries ⇢ modify them as needed ⇢ maintain
- Write our own generic version
We carefully investigated both options, and within the Android team, we decided it made more sense to write our own version. Our iOS team, however, opted to modify an existing library to avoid extra work setting up Kotlin Native [more on this later].
Let’s make a multi-platform wheel
At this point we knew we wanted to write our own SSE implementation but then we thought — why not write it in Kotlin multi-platform to allow sharing business logic between Android, iOS, and even other platforms in the future?
We are already doing this to share our core algorithm between Android, iOS and the backend. We gave a talk about this at KotlinConf — Sharing is caring! from KotlinConf — in case you’re interested in learning more.
Since this option made the most sense for our whole team, we decided to go for it.
PS: If you are new to Kotlin multi-platform, take a look at the official docs:
https://kotlinlang.org/docs/reference/multiplatform.html
Let’s dive into the details 🏊🏊♀️
Kotlin multi-platform projects are structured as shown below:
- Common: It should contain the common code to be shared between all the platforms a.k.a platform independent.
In our case, it contains major business logic and rules for SSE written once - JVM: It should contain implementation specific to JVM.
In our case, it containsOkHttp
as our HTTP client to fuel ⛽️ the SSE in the common code
Currently, implementation isn’t set up for platforms other than iOS since with our current setup, they need to use the Typescript API to consume shared code which affects performance [as compared to Kotlin].
That being said, our iOS team is working to set up Kotlin/Native so that they can directly use Kotlin 😍
Note: The diagram shows major platforms using JVM / JS / Native. That doesn’t mean you cannot use the library on any other JVM platform like Spring; the same applies to JS / Native.
What’s special with OkSSE 🎁
Surely there are lots of alternatives for SSE client; we created our library with the following goals:
- Follow W3C specification 📑 to build something generic and as per the standard which everyone can rely on
- Leverage Kotlin language features like sealed classes, lambda functions, extension function to provide a simple and easy API for developers
- Leverage Kotlin coroutines to make it super easy to write non-blocking code and provide easier concurrency management to users of the API
- Leverage Kotlin multiplatform to have a single business logic, which can be used by all platforms to have a single source of truth and minimize multiple implementation of the same thing while also avoiding different bugs 🐞 on different platforms
- Keep it lightweight — OkSSE has a very lightweight implementation. For Android, it has dex count of just 336 🦩
How to use it
You just need a coroutine scope to connect to SSE and start streaming all the events from the server.
Let’s look at an usage example on JVM / Android:
class SseSample {
val client = OkHttpClient.Builder().build()
val requestBuilder = Request.Builder()
fun main() = runBlocking {
withContext(Dispatchers.Default) {
val eventSource = connectToSse(
client,
requestBuilder,
random = Random(randomSeed),
logger = object : Logger {
// Various callbacks for logging
}
)
for (state in eventSource) {
// Triggered each time there is a new SSE
// state from server
println(">>>> state -> $state")
}
}
}
}
You can read the data from the event here 👇
for (state in eventSource) {
when (it) {
is EventSourceState.WithoutEvent -> null
is EventSourceState.WithEvent -> it.lastEvent.let { event ->
val data: String = event.data
// Parse the JSON string to your data models
}
}
}
The sample app provided in the repository is a great starting point in understanding how to use OkSSE library especially for JVM / Android.
Kicking it off ⚽️
We are currently using OkSSE in our Android app, and we are super excited to be sharing it with the tech community. We hope you give it a spin 💫 and let us know what you think.
Check out the sample and the GitHub repository to try it out! The code has a lot of comments and tests 💪🏻
OkSSE also comes with small things like logging: an exponential back-off retry mechanism to prevent constantly hitting your server when there is an error or no network — you can even provide your own HTTP client.
We hope to add bindings for other platforms and are happy to receive contributions from the amazing tech community 😎