精通 GraphQL 与 Ktor:Android 现代网络指南
Source: Dev.to

最初发表于 Medium:
介绍
现代 Android 应用需要灵活、高效且可扩展的网络解决方案。虽然 REST API 多年来一直是标准,但 GraphQL 已崭露头角,成为一种强大的替代方案,尤其适用于需要精确数据获取和降低网络开销的应用。与其为获取不同数据片段而调用多个端点,GraphQL 让你在一次请求中只获取所需的内容。
在我之前的文章中,我讨论了如何设置 Ktor,这是一款由 JetBrains 开发的现代 Kotlin‑first 网络框架。我们探讨了它如何提供轻量级的 Retrofit 替代方案。如果你还没有阅读过,我强烈建议查看,以便搭建你的基础客户端。你可以在这里找到文章:
Exploring Ktor: A Modern Networking Framework for Kotlin
现在,让我们更进一步,探索如何将 GraphQL 与 Ktor 集成,以构建高效的 API。无论你是初学者还是想要现代化你的技术栈,本指南都将涵盖从环境搭建到发起首个请求的全部内容。
什么是 GraphQL?
GraphQL 是一种用于 API 的查询语言,允许客户端请求恰好所需的数据——既不多也不少。
主要区别在于,REST 使用多个具有固定响应结构的端点,而 GraphQL 使用单一端点并通过灵活的查询来提供优化后的响应。这种带宽效率对于每一千字节都很重要的移动应用来说非常理想。
为什么在 Ktor 中使用 GraphQL?
- 最小开销 – 无需沉重的外部库,保持 APK 大小小巧。
- 完全控制 – 你可以精确定义请求和响应的处理方式。
- 跨平台就绪 – 相同的逻辑在 Kotlin Multiplatform (KMP) 中无缝运行。
- Kotlin‑优先 – 基于协程,无回调,并且能顺畅配合 Clean Architecture 与 MVVM。
项目设置
在集成 GraphQL 之前,确保你的 Android 项目中已经加入了 Ktor。将以下依赖添加到 app‑level build.gradle.kts:
dependencies {
implementation(platform("io.ktor:ktor-bom:3.1.2"))
implementation("io.ktor:ktor-client-android")
implementation("io.ktor:ktor-client-content-negotiation")
implementation("io.ktor:ktor-serialization-kotlinx-json")
implementation("io.ktor:ktor-client-logging")
}
在根目录的 build.gradle.kts 中启用 Kotlin Serialization 插件:
plugins {
id("org.jetbrains.kotlin.plugin.serialization") version "2.1.20"
}
理解 GraphQL 在 Ktor 中的工作原理
使用 GraphQL 时,每个操作通常都是对单一端点的 POST 请求。查询或变更(mutation)作为 JSON 请求体传递。
定义请求模型
@Serializable
data class GraphQLRequest(
val query: String,
val variables: Map<String, Any>? = null
)
定义通用响应包装器
@Serializable
data class GraphQLResponse<T>(
val data: T? = null,
val errors: List<GraphQLError>? = null
)
@Serializable
data class GraphQLError(val message: String)
开始你的第一次请求
让我们使用公共 GraphQL API 获取国家列表。首先,定义你的数据模型:
@Serializable
data class CountriesData(val countries: List<Country>)
@Serializable
data class Country(
val code: String,
val name: String,
val emoji: String,
val capital: String? = null
)
实现
suspend fun fetchCountries(): GraphQLResponse<CountriesData> {
val countryQuery = """
query {
countries {
code
name
emoji
capital
}
}
""".trimIndent()
return httpClient.post("https://countries.trevorblades.com/graphql") {
setBody(GraphQLRequest(query = countryQuery))
}.body()
}
处理错误和日志记录
GraphQL 即使查询逻辑出现错误,也可能返回 HTTP 200 状态码。始终检查错误列表:
val response = fetchCountries()
if (!response.errors.isNullOrEmpty()) {
response.errors.forEach { error ->
Log.e("GraphQL Error", error.message)
}
}
对于专业的日志记录,我推荐使用 Timber。我在后续的文章中写了关于将 Timber 与 Ktor 集成的详细指南。
详细指南
关于如何设置的详细指南请参阅:使用 Timber 和 Kotlin 实现轻松的 Android 日志记录
最终思考
将 GraphQL 与 Ktor 集成非常直接,为 Android 开发者提供了现代、灵活且 Kotlin 原生的网络栈。它与 MVVM 和 Clean Architecture 完美契合。通过利用统一的 HttpClient,你可以无缝处理 REST 和 GraphQL 两种请求。
实践参考的 GitHub 仓库
为了让本文更具实用性,我已发布了一个公开的 GitHub 仓库,演示如何使用真实的 GraphQL API 实现上文讨论的所有内容。
该项目的目标不仅是 “获取数据”,更在于展示如何在 Android 应用中以惯用的方式使用 Ktor 集成 GraphQL——而不是在其之上强行套用基于 REST 的抽象。
📂 GitHub 仓库:
https://github.com/your-username/ktor-graphql-android-example (请替换为实际的 URL)
Source: …
GraphQL 示例 – Android(Jetpack Compose + Ktor)
概览
一个 简洁、干净的 Android 示例,演示如何在 Jetpack Compose 应用中使用 Ktor 来调用 GraphQL API。
项目遵循 Clean Architecture 与 MVVM 原则,展示了地道的 GraphQL 处理方式,未使用 REST 风格的抽象(例如伪造的 HTTP 状态码或通用响应包装器)。
✨ 特性
- ✅ 使用 Ktor 集成 GraphQL API
- ✅ Jetpack Compose UI
- ✅ Clean Architecture(Data → Domain → UI)
- ✅ MVVM 单向数据流
- ✅ Kotlin 协程
- ✅ Koin 进行依赖注入
- ✅ 正确的 GraphQL 错误处理(
data与errors) - ✅ 无 Retrofit、无 REST‑style
CommonResponse
🔗 使用的 API(免费 & 公共)
Countries GraphQL API
https://countries.trevorblades.com/graphql
示例查询
query {
countries {
code
name
capital
}
}
该 API 的特点:
- 完全免费
- 无需身份验证
- 适合演示和学习
🏗️ 架构概览
下面是应用层级及其交互的高层示意图。每个组件保持独立,以提升可测试性、可维护性和可扩展性。
graph TD
UI[UI (Jetpack Compose)] --> ViewModel[ViewModel (Android Architecture Components)]
ViewModel --> Repository[Repository]
Repository -->|Local| RoomDB[(Room Database)]
Repository -->|Remote| Retrofit[(Retrofit API)]
Repository -->|Cache| DataStore[(DataStore / SharedPreferences)]
层级划分
| 层级 | 职责 | 关键技术 |
|---|---|---|
| UI | 渲染界面,处理用户交互 | Jetpack Compose, Material 3 |
| ViewModel | 保存 UI 状态,处理事件,跨配置保持 | Android ViewModel, Kotlin Coroutines, StateFlow |
| Repository | 在 ViewModel 与数据源之间调度数据流,实现业务规则 | Repository pattern, Clean Architecture |
| Data Sources | 提供具体的数据(本地 & 远程) | Room, Retrofit, OkHttp, DataStore, WorkManager(用于后台同步) |
| Domain (optional) | 封装用例 / 业务逻辑 | Use‑case classes, Kotlin Flows |
交互流程
- 用户操作 – UI 触发事件(例如按钮点击)。
- ViewModel – 接收事件,更新
StateFlow/LiveData,并调用相应的 repository 方法。 - Repository – 决定是从本地缓存(
Room/DataStore)读取还是发起网络请求(Retrofit)。 - Data Sources – 将数据(或错误)返回给上层。
- ViewModel – 发出新的 UI 状态,Compose UI 观察并相应地重新组合。
提示: 保持 UI 层 轻量 —— 只负责渲染状态并转发用户意图。所有逻辑应放在 ViewModel 或 Repository 中,便于在不依赖 Android 的情况下进行单元测试。
