EitherNet

EitherNet

多平台网络API响应处理框架

EitherNet是一个多平台网络API响应处理框架,主要用于Retrofit但可扩展到其他平台。它使用Kotlin密封类型提供类型安全的单一返回点,简化了错误处理流程。该框架支持自定义错误类型、结果处理、重试机制和测试功能,为开发者提供了灵活且强大的网络请求处理方案。

EitherNetAPIRetrofitKotlin网络请求Github开源项目

EitherNet

EitherNet 是一个多平台、可插拔且密封的 API 结果类型,用于建模网络 API 响应。目前,它仅在 JVM 上为 Retrofit 实现,但核心 API 定义在公共代码中,可以为其他平台实现。

以下 README 内容主要关注 Retrofit 实现。

使用方法

默认情况下,Retrofit 使用异常来传播错误。本库利用 Kotlin 密封类型来更好地模型化这些响应,提供类型安全的单一返回点,无需异常处理!

核心类型是 ApiResult<out T, out E>,其中 T 是成功类型,E 是可能的错误类型。

ApiResult 有两个密封子类型:SuccessFailureSuccess 类型为 T,没有错误类型;Failure 类型为 E,没有成功类型。Failure 又有四个密封子类型:Failure.NetworkFailureFailure.ApiFailureFailure.HttpFailureFailure.UnknownFailure。这允许通过一致的、非异常流程使用密封 when 分支简单处理结果。

when (val result = myApi.someEndpoint()) { is Success -> doSomethingWith(result.response) is Failure -> when (result) { is NetworkFailure -> showError(result.error) is HttpFailure -> showError(result.code) is ApiFailure -> showError(result.error) is UnknownFailure -> showError(result.error) } }

通常,用户代码只需为 Failure 情况显示一个通用错误消息,但密封子类型也允许更具体的错误消息或错误类型的可插拔性。

只需将端点返回类型更改为类型化的 ApiResult,并包含我们的调用适配器和委托转换器工厂。

interface TestApi { @GET("/") suspend fun getData(): ApiResult<SuccessResponse, ErrorResponse> } val api = Retrofit.Builder() .addConverterFactory(ApiResultConverterFactory) .addCallAdapterFactory(ApiResultCallAdapterFactory) .build() .create<TestApi>()

如果没有自定义错误返回类型,只需将错误类型设为 Unit

解码错误主体

如果要解码 HttpFailure 中的错误类型,请使用 @DecodeErrorBody 注解标记端点:

interface TestApi { @DecodeErrorBody @GET("/") suspend fun getData(): ApiResult<SuccessResponse, ErrorResponse> }

现在,4xx 或 5xx 响应将尝试将其错误主体(如果有)解码为 ErrorResponse。如果要根据状态码上下文解码错误主体,可以在自定义 Retrofit Converter 中从注解中检索 @StatusCode 注解。

// 在您自己的转换器工厂中 override fun responseBodyConverter( type: Type, annotations: Array<out Annotation>, retrofit: Retrofit ): Converter<ResponseBody, *>? { val (statusCode, nextAnnotations) = annotations.statusCode() ?: return null val errorType = when (statusCode.value) { 401 -> Unauthorized::class.java 404 -> NotFound::class.java // ... } val errorDelegate = retrofit.nextResponseBodyConverter<Any>(this, errorType.toType(), nextAnnotations) return MyCustomBodyConverter(errorDelegate) }

注意,内容长度为 0 的错误主体将被跳过。

可插拔性

某些 API 的常见模式是返回多态的 200 响应,其中数据需要动态解析。考虑以下示例:

{ "ok": true, "data": { ... } }

同一 API 在错误事件中可能返回这种结构:

{ "ok": false, "error_message": "请重试。" }

这很难用单一具体类型建模,但使用 ApiResult 很容易处理。只需在自定义 Retrofit Converter 中抛出带有解码错误类型的 ApiException,它将自动作为带有该错误实例的 Failure.ApiFailure 类型呈现。

@GET("/") suspend fun getData(): ApiResult<SuccessResponse, ErrorResponse> // 在您自己的转换器工厂中 class ErrorConverterFactory : Converter.Factory() { override fun responseBodyConverter( type: Type, annotations: Array<out Annotation>, retrofit: Retrofit ): Converter<ResponseBody, *>? { // 这返回一个 `@ResultType` 实例,可用于通过 toType() 获取错误类型 val (errorType, nextAnnotations) = annotations.errorType() ?: return null return ResponseBodyConverter(errorType.toType()) } class ResponseBodyConverter( private val errorType: Type ) : Converter<ResponseBody, *> { override fun convert(value: ResponseBody): String { if (value.isErrorType()) { val errorResponse = ... throw ApiException(errorResponse) } else { return SuccessResponse(...) } } } }

重试

网络请求的一个常见模式是使用指数退避进行重试。EitherNet 提供了一个高度可配置的 retryWithExponentialBackoff() 函数用于这种情况。

// 默认值供参考 val result = retryWithExponentialBackoff( maxAttempts = 3, initialDelay = 500.milliseconds, delayFactor = 2.0, maxDelay = 10.seconds, jitterFactor = 0.25, onFailure = null, // 可选的失败回调,用于日志记录 ) { api.getData() }

测试

EitherNet 提供了一个 测试夹具 工件,其中包含 EitherNetController API,允许轻松测试 EitherNet API。这类似于 OkHttp 的 MockWebServer,可以为特定端点排队结果。

只需在测试中使用 newEitherNetController() 函数之一创建一个新的控制器实例。

val controller = newEitherNetController<PandaApi>() // 具体化类型

然后,您可以从中访问底层模拟的 api 属性,并将其传递给被测试的对象。

// 从控制器获取 api 实例并传递给被测试的对象 val provider = PandaDataProvider(controller.api)

最后,根据需要为端点排队结果。

// 在测试中,您可以为特定端点排队结果 controller.enqueue(PandaApi::getPandas, ApiResult.success("Po"))

您还可以选择传入完整的挂起函数,如果需要动态行为:

controller.enqueue(PandaApi::getPandas) { // 这是一个挂起函数! delay(1000) ApiResult.success("Po") }

在使用依赖注入的集成测试中,您可以在测试模块中提供控制器及其底层 API,并替换标准模块。这与 Anvil 配合得特别好。

@ContributesTo( scope = UserScope::class, replaces = [PandaApiModule::class] // 替换标准模块 ) @Module object TestPandaApiModule { @Provides fun providePandaApiController(): EitherNetController<PandaApi> = newEitherNetController() @Provides fun providePandaApi( controller: EitherNetController<PandaApi> ): PandaApi = controller.api }

然后,您可以在测试中注入控制器,而 PandaApi 的用户将获得您的测试实例。

Java 互操作性

对于 Java 互操作性,JavaEitherNetControllers.enqueueFromJava 提供了有限的 API。

验证

EitherNetController 会在后台对 API 端点进行一些小型验证。如果您想在此基础上添加自己的验证,可以通过 ServiceLoader 提供 ApiValidator 的实现。有关更多信息,请参阅 ApiValidator 的文档。

安装

Maven Central

dependencies { implementation("com.slack.eithernet:eithernet:<版本>") implementation("com.slack.eithernet:eithernet-integration-retrofit:<版本>") // 测试夹具 testImplementation(testFixtures("com.slack.eithernet:eithernet:<版本>")) }

开发版本的快照可在 Sonatype 的 snapshots 仓库中获得。

许可证

Copyright 2020 Slack Technologies, LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

编辑推荐精选

Pixmax

Pixmax

一站式AI短剧创作平台

Pixmax专注打造下一代“ AI 视觉创作引擎”,整合行业顶尖 AI 大模型、工工业级精准控制及企业级协同管理功能,是全方位的 AI 内容创作平台。

豆包

豆包

字节跳动旗下 AI 智能助手

字节跳动旗下 AI 智能助手

GPT Plus|Pro充值

GPT Plus|Pro充值

GPT充值

支持 ChatGPT Plus / Pro 充值服务,支付便捷,自动发货,售后可查。

GPT Image 2中文站

GPT Image 2中文站

AI 图片生成平台

GPT Image 2 是面向用户的 AI 图片生成平台,支持文生图、图生图及多模型创意工作流。

Vecbase

Vecbase

你的AI Agent团队

Vecbase 是专为 AI 团队打造的智能工作空间,将数据管理、模型协作与知识沉淀整合于一处。算法、产品与业务在同一平台无缝协同,让从数据到 AI 应用的落地更快一步。

音述AI

音述AI

全球首个AI音乐社区

音述AI是全球首个AI音乐社区,致力让每个人都能用音乐表达自我。音述AI提供零门槛AI创作工具,独创GETI法则帮助用户精准定义音乐风格,AI润色功能支持自动优化作品质感。音述AI支持交流讨论、二次创作与价值变现。针对中文用户的语言习惯与文化背景进行专门优化,支持国风融合、C-pop等本土音乐标签,让技术更好地承载人文表达。

QoderWork

QoderWork

阿里Qoder团队推出的桌面端AI智能体

QoderWork 是阿里推出的本地优先桌面 AI 智能体,适配 macOS14+/Windows10+,以自然语言交互实现文件管理、数据分析、AI 视觉生成、浏览器自动化等办公任务,自主拆解执行复杂工作流,数据本地运行零上传,技能市场可无限扩展,是高效的 Agentic 生产力办公助手。

lynote.ai

lynote.ai

一站式搞定所有学习需求

不再被海量信息淹没,开始真正理解知识。Lynote 可摘要 YouTube 视频、PDF、文章等内容。即时创建笔记,检测 AI 内容并下载资料,将您的学习效率提升 10 倍。

AniShort

AniShort

为AI短剧协作而生

专为AI短剧协作而生的AniShort正式发布,深度重构AI短剧全流程生产模式,整合创意策划、制作执行、实时协作、在线审片、资产复用等全链路功能,独创无限画布、双轨并行工业化工作流与Ani智能体助手,集成多款主流AI大模型,破解素材零散、版本混乱、沟通低效等行业痛点,助力3人团队效率提升800%,打造标准化、可追溯的AI短剧量产体系,是AI短剧团队协同创作、提升制作效率的核心工具。

seedancetwo2.0

seedancetwo2.0

能听懂你表达的视频模型

Seedance two是基于seedance2.0的中国大模型,支持图像、视频、音频、文本四种模态输入,表达方式更丰富,生成也更可控。

下拉加载更多