
Mock API responses and assert requests with a readable DSL; serialization-agnostic core, extensible HttpApythia adapter, unified API across HTTP clients, optional JSON extension, inspect actual request data.
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:
http artifact and the HttpApythia interface are completely independent from any serialization library.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:
HttpApythia abstract class, which serves as the main entry point for mocking and assertions.HttpApythia, you can provide configuration objects specific to each extension.
For example, the JSON extension can accept a global Json instance or custom settings for all its operations, while other extensions can have their own separate configurations.HttpApythia to connect Apythia to the mocking solution of your production HTTP client (e.g., Ktor’s MockEngine).Apythia’s core is independent of serialization. Optional extensions allow seamless integration:
Adds support for JSON bodies and JSON assertions using Kotlinx Serialization:
jsonObjectBody { ... } and jsonArrayBody { ... } allow building response JSON bodies using Kotlinx Serialization DSL builders (JsonObjectBuilder, JsonArrayBuilder), providing type-safe, natural syntax.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:
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 💙.
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:
http artifact and the HttpApythia interface are completely independent from any serialization library.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:
HttpApythia abstract class, which serves as the main entry point for mocking and assertions.HttpApythia, you can provide configuration objects specific to each extension.
For example, the JSON extension can accept a global Json instance or custom settings for all its operations, while other extensions can have their own separate configurations.HttpApythia to connect Apythia to the mocking solution of your production HTTP client (e.g., Ktor’s MockEngine).Apythia’s core is independent of serialization. Optional extensions allow seamless integration:
Adds support for JSON bodies and JSON assertions using Kotlinx Serialization:
jsonObjectBody { ... } and jsonArrayBody { ... } allow building response JSON bodies using Kotlinx Serialization DSL builders (JsonObjectBuilder, JsonArrayBuilder), providing type-safe, natural syntax.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:
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 💙.