In ancient times, the Oracle of Delphi—Pythia—revealed truths hidden to mortal eyes. Today, your API calls are the hidden realm, filled with subtle mistakes, unmocked responses, and unexpected behaviors.
Enter Apythia – your magical oracle for API communication, revealing hidden truths in your Kotlin Multiplatform projects through mocking and assertions — all while hiding the underlying API implementation.
Apythia helps you test your API/network logic confidently with a clear, expressive DSL:
- Mock API responses easily – define exactly how your API client should respond.
- Assert requests elegantly – verify that the requests your code sent match your expectations.
- DSL-first approach – both mocking and assertions are intuitive, readable, and powerful.
- Single unified API – interact with one DSL, regardless of whether your underlying implementation is Ktor, OkHttp, any other API library or custom implementation.
- Serialization-agnostic core – the main
httpartifact and theHttpApythiainterface are completely independent from any serialization library. - Kotlin Multiplatform support – works for Android, iOS, and JVM targets.
With Apythia, your API logic is predictable, testable, and clearly defined.
Apythia is fully modular and extensible. You pick only what you need.
This is the heart of Apythia:
- Contains all HTTP-related abstractions and the DSL for mocking responses and asserting requests.
- Defines the
HttpApythiaabstract class, which serves as the main entry point for mocking and assertions. - No serialization dependency — everything works with raw strings or bytes by default.
- Provides a DSL extension configuration mechanism:
- When constructing any
HttpApythia, you can provide configuration objects specific to each extension. For example, the JSON extension can accept a globalJsoninstance or custom settings for all its operations, while other extensions can have their own separate configurations.
- When constructing any
- Fully extensible — you can implement your own
HttpApythiato connect Apythia to the mocking solution of your production HTTP client (e.g., Ktor’sMockEngine).
Apythia’s core is independent of serialization. Optional extensions allow seamless integration:
Adds support for JSON bodies and JSON assertions using Kotlinx Serialization:
- Functions like
jsonObjectBody { ... }andjsonArrayBody { ... }allow building response JSON bodies using Kotlinx Serialization DSL builders (JsonObjectBuilder,JsonArrayBuilder), providing type-safe, natural syntax. - Provides similar DSLs for asserting JSON data in requests.
- Optional — include it only if your project uses Kotlinx Serialization.
- Can be used as a reference to implement your own DSL extensions for other formats or serialization libraries.
Almost every main block in the assertion DSL (e.g., body, headers) gives you access
to the actual request data, allowing you to write custom DSL extensions or implement additional checks on top of the provided DSL.
Apythia includes ready-made implementations of HttpApythia for popular clients:
Backed by Ktor client.
Ideal for projects using Ktor networking.
Includes the core http module transitively.
Backed by OkHttp.
Ideal for Android/JVM projects.
Includes the core http module transitively.
Since HttpApythia is an abstract class, you can implement it to connect Apythia to the mocking solution
of your production HTTP client (for example, Ktor’s MockEngine or your own client).
This allows you to use all of Apythia’s platform-independent DSL, mocking, and assertion features,
while plugging in your own HTTP client for request execution.
Use the BOM to ensure consistent and binary-compatible versions.
[versions]
apythia-bom = "SPECIFY_VERSION"
[libraries]
apythia-bom = { module = "io.github.ackeecz:apythia-bom", version.ref = "apythia-bom" }
# Core-only module — use ONLY if you implement your own HttpApythia
apythia-http = { module = "io.github.ackeecz:apythia-http" }
# For Ktor
apythia-http-ktor = { module = "io.github.ackeecz:apythia-http-ktor" }
# For OkHttp
apythia-http-okhttp = { module = "io.github.ackeecz:apythia-http-okhttp" }
# Optional JSON + Kotlinx Serialization support
apythia-http-ext-json-kotlinx-serialization = { module = "io.github.ackeecz:apythia-http-ext-json-kotlinx-serialization" }dependencies {
// Always use BOM
testImplementation(platform(libs.apythia.bom))
// Choose your HTTP implementation
testImplementation(libs.apythia.http.ktor)
// OR
testImplementation(libs.apythia.http.okhttp)
// Optional: JSON DSL extension
testImplementation(libs.apythia.http.ext.json.kotlinx.serialization)
// Only needed if writing your own HttpApythia
// testImplementation(libs.apythia.http)
}
commonTest {
dependencies {
implementation(platform(libs.apythia.bom))
// Choose your HTTP implementation
implementation(libs.apythia.http.ktor)
// Optional JSON support
implementation(libs.apythia.http.ext.json.kotlinx.serialization)
// Core-only for custom implementation
// implementation(libs.apythia.http)
}
}private lateinit var httpApythia: HttpApythia
private lateinit var underTest: RemoteDataSource
class RemoteDataSourceImplTest : FunSpec({
val ktorHttpApythia = KtorHttpApythia().also { httpApythia = it }
beforeEach {
ktorHttpApythia.beforeEachTest()
val httpClient = HttpClient(ktorHttpApythia.mockEngine)
underTest = RemoteDataSourceImpl(httpClient)
}
afterEach {
ktorHttpApythia.afterEachTest()
}
// Then use HttpApythia interface in your tests. This will make them decoupled from the underlying HTTP client.
})Tip: It’s recommended to create a JUnit rule or Kotest extension (depending on your testing framework)
to automatically handle setup and teardown of HttpApythia instances, avoiding repetitive boilerplate in each test.
httpApythia.mockNextResponse {
statusCode(204)
headers {
header("X-Custom-Header", "customValue")
header("Accept", "application/json")
}
jsonObjectBody {
put("customKey", "customValue")
}
}httpApythia.assertNextRequest {
method(HttpMethod.GET)
url {
path("/api/v1/sample.php")
query {
parameter("param", 1)
parameters("param2", listOf("value1", "value2"))
}
}
body {
jsonObject {
put("key", "value")
}
}
}KtorHttpApythia {
kotlinxSerializationJsonConfig {
allowTrailingComma = true
// Add other settings as needed
}
}KtorHttpApythia {
// Provide configuration for third-party or custom extensions. For more info see
// DslExtensionConfig documentation.
dslExtensionConfig(...)
}Some of Apythia’s APIs are marked as experimental.
This follows the standard Kotlin experimental / @OptIn conventions — meaning:
- These APIs are stable in behavior and safe to use in production.
- Their public API surface may evolve in future releases based on:
- Real-world feedback
- DSL improvements
- New features or extension modules
- Refinement of cross-platform abstractions
When using experimental APIs, you may need to update your code when upgrading to new versions, especially where the API is annotated with Kotlin’s experimental markers.
We welcome feedback from users — it helps guide the evolution of Apythia’s experimental features.
Developed by Ackee team with 💙.