Hello, Kotlin SDK
- Date
- Marty Pitt
Orbital is a platform for automating integration between microservices. Developers can ask for the data they need, and let Orbital handle all the integration work.
We’ve just released the first version of our Kotlin SDK for invoking Orbital’s integration engine directly inside your Kotlin code. Our Kotlin SDK gives rich, type-safe integration across databases, APIs, kafka topics and more, all without writing any integration code.
In this post
- A video showing our Kotlin SDK
- Background - Semantic APIs with Taxi and Kotlin
- Type safe integration with our new Kotlin SDK
- Linking Streaming data from Kafka with Microservices
- Oribtal’s amazing observability
Watch the video
The content of this blog is also covered in this video, if that’s more your cup-o-tea!
Background: Semantic APIs with Taxi and Kotlin's typealias
Semantic metadata allows developers to build a library of simple terms that describe data attributes between systems.
Data seldom exists in a silo - keys from one system can be fed to another to provide data or capabilities. Semantic Metadata is a way of capturing these relationships, and using them to drive software automation.
This is a really powerful technique for building autonomous systems, which self-integrate and self-repair. We go into this is much more detail in this post, which is worth reading.
Semantic Metadata using Kotlin
Taxi has had support generating Kotlin typealias
for some time, using the Taxi Kotlin plugin.
This allows developers building microservices to publish fine-grained semantic schemas directly from their code.
Of course, there’s other ways to publish semantic metadata, such as directly in OpenAPI schemas, or Protobuf specs, but this is a Kotlin blog, so we’ll stay in code.
For example, consider a Spring Boot REST API that tells me which streaming services I can watch a movie on:
@DataType("com.demo.FilmId")
typealias FilmId = Int
@DataType("com.demo.StreamingProviderName")
typealias StreamingProviderName = String
@DataType("com.demo.StreamingProviderPrice")
typealias StreamingProviderPrice = String
// Response object
data class StreamingProvider(
val name: StreamingProviderName,
val pricePerMonth: StreamingProviderPrice
)
// REST API
@GetMapping("/films/{filmId}/streamingProviders")
fun getPlacesWhereFilmIsPlaying(@PathVariable("filmId") filmId: FilmId): StreamingProvider {
//...
}
Type safe querying
The Kotlin SDK lets you write type-safe queries that ask for data, without specifying where to fetch it from, or how to enrich it.
This is really powerful, as it means consumers of data are no longer tightly-coupled to producer APIs.
For example, we can ask Orbital to stitch some data from multiple a database of Films, together with data that tells me where I can watch it.
First, we need to define a data class, containing the fields we’re interested in:
data class MyResponseObject(
// Grab some fields from our database:
val id: FilmId,
val title: Title,
// Along with some from a REST API:
val availableToWatchAt: StreamingProviderName,
val costPerMonth: StreamingProviderPrice
)
Then, Use Orbital’s Kotlin sdk to ask orbital to fetch the data for us:
val response = find<List<Film>>()
.asA<List<MyResponseObject>>()
// Specify where Orbital is running
.run(http("http://localhost:9022"))
.toFlux()
.subscribe { printLn("Received a response: ${objectMapper.writeValueAsString(event)}") }
Under the covers, this code constructs a TaxiQL query
and sends it to Orbital, running at localhost:9022
.
Orbital then generates an integration on-the-fly, fetching data from our database first, then enriching it with API calls, before returning the results
Getting richer
If we added more fields to our response object that come from a 3rd data source, this time asking for reviews of our films:
data class MyResponseObject(
// Grab some fields from our database:
val id: FilmId,
val title: Title,
// Along with some from a REST API:
val availableToWatchAt: StreamingProviderName,
val costPerMonth: StreamingProviderPrice,
val reviewScore: FilmReviewScore,
val review: ReviewText
)
This time, executing our query Orbital does more work for us:
Here, Orbital is fetching data from multiple sources. The work happens in parallel, to keep the integration snappy.
Streaming query results
So far, Orbital has been executing the query, enriching the data, and returning to our Kotlin client once the query is finished.
However, we can ask Orbital to stream the data as soon as it’s available, operating on a stream.
This means we get data back much sooner. It’s as simple as changing the the transport from http
to httpStream
:
val response = find<List<Film>>()
.asA<List<Response>>()
.run(httpStream("http://localhost:9022"))
.toFlux()
.subscribe { printLn("Received a message: ${objectMapper.writeValueAsString(event)}") }
Now, when we run the query, we see results stream in almost instantly.
Querying Kafka
Orbital can also handle querying infinite streams of data, such as from a Kafka topic.
All that’s different is we change the verb from find
to stream
.
Let’s subscribe to a stream of new release announcements, which are published on Kafka:
val response = stream<NewReleaseAnnouncement>()
.asA<List<Response>>()
.run(httpStream("http://localhost:9022"))
.toFlux()
.subscribe { printLn("Received a message: ${objectMapper.writeValueAsString(event)}") }
Here, Orbital is enriching the data on every message, enriching with a database query and a series of Rest API calls.
However, the client code has remained incredibly simple!
Observability
Even though our queries were triggered by the Kotlin client, the orchestration was performed by Orbital - which means we get Orbital’s amazing observability, with zero effort.
The profiler shows us lots of great information - let’s take a quick look at what’s available
High level execution plan
The high level execution plan shows us exactly how the integration was executed - which systems were invoked, and how data was passed between them.
Call sequence diagram
We can also see a classic sequence diagram, showing each call between the systems. Clicking on each call shows us the request that was sent, and the response we got back.
Cell-level lineage
We can go even deeper. Clicking on any value returned shows the actual values passed between the systems to derive the provided values.
Grab the bits
You can grab the artefacts directly from Maven Central, or view the code over on Github. Also, check out the full API reference over in our docs.
<!-- For writing queries -->
<dependency>
<groupId>com.orbitalhq</groupId>
<artifactId>kotlin-client</artifactId>
<version>0.1.0</version>
</dependency>