EitherNet 是一个多平台、可插拔且密封的 API 结果类型,用于建模网络 API 响应。目前,它仅在 JVM 上为 Retrofit 实现,但核心 API 定义在公共代码中,可以为其他平台实现。
以下 README 内容主要关注 Retrofit 实现。
默认情况下,Retrofit 使用异常来传播错误。本库利用 Kotlin 密封类型来更好地模型化这些响应,提供类型安全的单一返回点,无需异常处理!
核心类型是 ApiResult<out T, out E>,其中 T 是成功类型,E 是可能的错误类型。
ApiResult 有两个密封子类型:Success 和 Failure。Success 类型为 T,没有错误类型;Failure 类型为 E,没有成功类型。Failure 又有四个密封子类型:Failure.NetworkFailure、Failure.ApiFailure、Failure.HttpFailure 和 Failure.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 互操作性,JavaEitherNetControllers.enqueueFromJava 提供了有限的 API。
EitherNetController 会在后台对 API 端点进行一些小型验证。如果您想在此基础上添加自己的验证,可以通过 ServiceLoader 提供 ApiValidator 的实现。有关更多信息,请参阅 ApiValidator 的文档。
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.


AI辅助编程,代码自动修复
Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。


AI一键生成PPT,就用博思AIPPT!
博思AIPPT,新一代的AI生成PPT平台,支持智能生成PPT、AI美化PPT、文本&链接生成PPT、导入Word/PDF/Markdown文档生成PPT等,内置海量精美PPT模板,涵盖商务、教育、科技等不同风格,同时针对每个页面提供多种版式,一键自适应切换,完美适配各种办公场景。


AI赋能电商视觉革命,一站式智能商拍平台
潮际好麦深耕服装行业,是国内AI试衣效果最好的软件。使用先进AIGC能力为电商卖家批量提供优质的、低成本的商拍图。合作品牌有Shein、Lazada、安踏、百丽等65个国内外头部品牌,以及国内10万+淘宝、天猫、京东等主流平台的品牌商家,为卖家节省将近85%的出图成本,提升约3倍出图效率,让品牌能够快速上架。


企业专属的AI法律顾问
iTerms是法大大集团旗下法律子品牌,基于最先进的大语言模型(LLM)、专业的法律知识库和强大的智能体架构,帮助企业扫清合规障碍,筑牢风控防线,成为您企业专属的AI法律顾问。


稳定高效的流量提升解决方案,助力品牌曝光
稳定高效的流量提升解决方案,助力品牌曝光


最新版Sora2模型免费使用,一键生成无水印视频
最新版Sora2模型免费使用,一键生成无水印视频


实时语音翻译/同声传译工具
Transly是一个多场景的AI大语言模型驱动的同声传译、专业翻译助手,它拥有超精准的音频识别翻译能力,几乎零延迟的使用体验和支持多国语言可以让你带它走遍全球,无论你是留学生、商务人士、韩剧美剧爱好者,还是出国游玩、多国会议、跨国追星等等,都可以满足你所有需要同传的场景需求,线上线下通用,扫除语言障碍,让全世界的语言交流不再有国界。


选题、配图、成文,一站式创作,让内容运营更高效
讯飞绘文,一个AI集成平台,支持写作、选题、配图、排版和发布。高效生成适用于各类媒体的定制内容,加速品牌传播,提升内容营销效果。


最强AI数据分析助手
小浣熊家族Raccoon,您的AI智能助手,致力于通过先进的人工智能技术,为用户提供高效、便捷的智能服务。无论是日常咨询还是专业问题解答,小浣熊都能以快速、准确的响应满足您的需求,让您的生活更加智能便捷。


像人一样思考的AI智能体
imini 是一款超级AI智能体,能根据人类指令,自主思考、自主完成、并且交付结果的AI智能体。
最新AI工具、AI资讯
独家AI资源、AI项目落地

微信扫一扫关注公众号